00001 #include <unistd.h>
00002 #include <sys/types.h>
00003 #include <fcntl.h>
00004 #include <linux/fb.h>
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <stdarg.h>
00008 #include <errno.h>
00009 #include <sys/ioctl.h>
00010 #include <sys/mman.h>
00011 #include <math.h>
00012 #include <err.h>
00013 #include <stdbool.h>
00014 #include <sys/time.h>
00015 #include <time.h>
00016 #include <signal.h>
00017 #include <termios.h>
00018 #include <pthread.h>
00019 #include <linux/input.h>
00020 #include <sys/un.h>
00021 #include <sys/socket.h>
00022
00023
00024 #include "libinline.h"
00025 #include "libcutils.h"
00026 #include "libgui.h"
00027
00028 using namespace android;
00029
00030 struct ASC_PRIV_DATA;
00031 struct ASC {
00032 ASC_PRIV_DATA* priv_data;
00033 char* data;
00034 int size;
00035 int w;
00036 int h;
00037 char pixfmtName[32];
00038 };
00039
00040 static bool needLog = true;
00041 #define LOG(fmt, arg...) ({static bool __logged=false; if (needLog||!__logged){_LOG("%s" fmt "%s", needLog?"":"--------rare case--------", ##arg, needLog?"":"\n\n");__logged=true;}})
00042 #define LOGI(fmt, arg...) LOG("--------" fmt "\n\n", ##arg)
00043 #define ABORT(fmt, arg...) ({_LOG(fmt ". Now exit", ##arg); exit(0);})
00044 #define ABORT_ERRNO(fmt, arg...) ({_LOG(fmt " [errno %d(%s)] Now exit", errno, strerror(errno), ##arg); exit(0);})
00045
00046 static void _LOG(const char* format, ...) {
00047 char buf[4096];
00048 int cnt;
00049 va_list va;
00050 struct timespec ct;
00051 struct tm * st;
00052 clock_gettime(CLOCK_REALTIME, &ct);
00053 st = localtime(&ct.tv_sec);
00054 cnt = sprintf(buf, "%02d/%02d %02d:%02d:%02d.%03d [ASC %d] ", st->tm_mon+1, st->tm_mday, st->tm_hour, st->tm_min, st->tm_sec, (int)(ct.tv_nsec/1000000), gettid());
00055 va_start(va, format);
00056 cnt += vsnprintf(buf+cnt, sizeof(buf)-cnt, format, va);
00057 va_end(va);
00058 if (cnt > sizeof(buf)) cnt = sizeof(buf); else if (cnt <= 0) {cnt = 7; strcpy(buf, "LogErr");};
00059 if (buf[cnt-1]==0) cnt--;
00060 if (buf[cnt-1]!='\n') buf[cnt++] = '\n';
00061 write(STDERR_FILENO, buf, cnt);
00062 }
00063
00064 static bool isPaused = false;
00065 static bool isScreenOff = false;
00066 static char* blackscreen = NULL;
00067 static int blackscreen_extra_count = 0;
00068
00069 static Mutex mutex;
00070 static Condition cond;
00071
00072 static bool isFirstTime = true;
00073
00074 static void chkDev() {
00075 char k[128] = {0};
00076 char _sn[256] = {0};
00077 char *sn = _sn;
00078 char hb[4+1] = {'0','0','0','0', 0};
00079 char now[6+1] = {0};
00080 const char* es;
00081 char* ds;
00082 char* err;
00083 int i=0, esLen, snLen, dsLen;
00084 unsigned int ec, sc, dc;
00085 struct timespec ct;
00086 struct tm * st;
00087
00088 es=getenv("ASC_");
00089 if (!es || !es[0]) ABORT("!nes");
00090 esLen = strlen(es);
00091 if (esLen%(2*6) != 0) ABORT("!esl");
00092 dsLen = esLen/2;
00093
00094
00095 k[i=0] = 'n'; k[++i] = 'e'; k[++i] = 't'; k[++i] = '.'; k[++i] = 'h'; k[++i] = 'o'; k[++i] = 's'; k[++i] = 't'; k[++i] = 'n'; k[++i] = 'a'; k[++i] = 'm'; k[++i] = 'e'; k[++i] = 0;
00096 property_get(k, sn, " ");
00097 snLen = strlen(sn);
00098 if (snLen > 8) {
00099 sn += 8;
00100 snLen -= 8;
00101 } else {
00102
00103 k[i=0] = 'r'; k[++i] = 'o'; k[++i] = '.'; k[++i] = 's'; k[++i] = 'e'; k[++i] = 'r'; k[++i] = 'i'; k[++i] = 'a'; k[++i] = 'l'; k[++i] = 'n'; k[++i] = 'o'; k[++i] = 0;
00104 property_get(k, sn, " ");
00105 snLen = strlen(sn);
00106 }
00107
00108 if ( dsLen != (snLen+6-1)/6*6 ) ABORT("!esms %d %d %d", snLen, (snLen+6-1)/6*6, dsLen);
00109
00110 ds = (char*)calloc(dsLen+1, 1);
00111 for(i=0; i < dsLen; i++) {
00112
00113 hb[2] = es[i*2];
00114 hb[3] = es[i*2+1];
00115 ec = (unsigned int)strtoul(hb, &err, 16);
00116 if (err&&err[0]) ABORT("!ec", err);
00117 sc = (unsigned int)(unsigned char)sn[i%snLen];
00118 dc = ec ^ sc;
00119 if (dc < '0' || dc > '9') ABORT("!dcd");
00120 ds[i] = (char)dc;
00121 }
00122 for (i = 6; i < dsLen; i += 6)
00123 if ( 0 != memcmp(ds, &ds[i], 6)) ABORT("!dsfd");
00124
00125 clock_gettime(CLOCK_REALTIME, &ct);
00126 st = localtime(&ct.tv_sec);
00127 sprintf(now, "%02d%02d%02d", (st->tm_year+1900-2000), st->tm_mon+1, st->tm_mday);
00128
00129 if (memcmp(now, ds, 6) > 0) ABORT("!to");
00130 free(ds);
00131 }
00132
00133 static void* thread_cmd_socket_server(void* thd_param) {
00134 int socket_server_fd = (int)thd_param;
00135 for(;;) {
00136 LOG("accept");
00137 int connection_fd = accept(socket_server_fd, NULL, NULL);
00138 if (connection_fd == -1) {
00139 LOG("accept err %d", errno);
00140 continue;
00141 }
00142
00143 for(;;) {
00144 unsigned char cmd;
00145 LOG("read cmd");
00146 if (read(connection_fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
00147 LOG("read err %d", errno);
00148 break;
00149 }
00150 LOGI("handle cmd: %c (%d)", cmd, cmd);
00151
00152 AutoMutex autoLock(mutex);
00153 switch (cmd) {
00154 case '+':
00155 if (isPaused) {
00156 isPaused = false;
00157 cond.signal();
00158 }
00159 break;
00160 case '-':
00161 if (!isPaused) {
00162 isPaused = true;
00163 cond.signal();
00164 }
00165 break;
00166 case '1':
00167 isScreenOff = isPaused = false;
00168 cond.signal();
00169 break;
00170 case '0':
00171 isScreenOff = isPaused = true;
00172 cond.signal();
00173 break;
00174 }
00175 }
00176
00177 LOG("close cmd connection");
00178 close(connection_fd);
00179 }
00180 return 0;
00181 }
00182
00183 static int touch_dev_fd = -1;
00184
00185 static void* thread_touch_socket_server(void* thd_param) {
00186 int socket_server_fd = (int)thd_param;
00187 for(;;) {
00188 LOG("accept");
00189 int connection_fd = accept(socket_server_fd, NULL, NULL);
00190 if (connection_fd == -1) {
00191 LOG("accept err %d", errno);
00192 continue;
00193 }
00194
00195 struct input_event event = {0};
00196 const int event_core_size = (((char*)&event.value) + sizeof(event.value)) - ((char*)&event.type);
00197 for(;;) {
00198 LOG("read touch event");
00199 if (read(connection_fd, &event.type, event_core_size) != event_core_size) {
00200 LOG("read err %d", errno);
00201 break;
00202 }
00203 LOGI("handle touch event %d %d %d", event.type, event.code, event.value);
00204 if (write(touch_dev_fd, &event, sizeof(event)) != sizeof(event)) {
00205 LOG("write err %d", errno);
00206 break;
00207 }
00208 }
00209
00210 LOG("close touch connection");
00211 close(connection_fd);
00212 }
00213 return 0;
00214 }
00215
00216 static void create_cmd_socket_server() {
00217 char* socket_name = getenv("ASC_CMD_SOCKET");
00218 if (socket_name && socket_name[0]) {
00219
00220 LOG("c s r %s", socket_name);
00221 int socket_server_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
00222 if (socket_server_fd == -1) {
00223 LOG("socket err %d", errno);
00224 return;
00225 }
00226
00227 struct sockaddr_un addr = {0};
00228 addr.sun_family = AF_LOCAL;
00229 int namelen = strlen(socket_name);
00230 if (1+namelen > sizeof(addr.sun_path)) ABORT("socket name too long");
00231 memcpy(&addr.sun_path[1], socket_name, namelen);
00232 int addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + namelen;
00233
00234 LOG("bnd");
00235 if (bind(socket_server_fd, (struct sockaddr*)&addr, addrlen)) {
00236 LOG("bind err %d", errno);
00237 return;
00238 }
00239
00240 LOG("lstn");
00241 if (listen(socket_server_fd, 1)) {
00242 LOG("listen err %d", errno);
00243 return;
00244 }
00245
00246 LOG("cthd");
00247 pthread_t thd;
00248 int err = pthread_create(&thd, NULL, thread_cmd_socket_server, (void*)socket_server_fd);
00249 if (err) {
00250 LOG("pthread_create err %d", err);
00251 return;
00252 }
00253 }
00254 }
00255
00256 static void create_touch_socket_server() {
00257 char* socket_name = getenv("ASC_TOUCH_SOCKET");
00258 if (socket_name && socket_name[0]) {
00259
00260 LOG("o t d %s", socket_name);
00261 touch_dev_fd = open(socket_name, O_WRONLY);
00262 if (touch_dev_fd==-1) {
00263 LOG("open err %d", errno);
00264 return;
00265 }
00266
00267 LOG("c s r %s", socket_name);
00268 int socket_server_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
00269 if (socket_server_fd == -1) {
00270 LOG("socket err %d", errno);
00271 return;
00272 }
00273
00274 struct sockaddr_un addr = {0};
00275 addr.sun_family = AF_LOCAL;
00276 int namelen = strlen(socket_name);
00277 if (1+namelen > sizeof(addr.sun_path)) ABORT("socket name too long");
00278 memcpy(&addr.sun_path[1], socket_name, namelen);
00279 int addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + namelen;
00280
00281 LOG("bnd");
00282 if (bind(socket_server_fd, (struct sockaddr*)&addr, addrlen)) {
00283 LOG("bind err %d", errno);
00284 return;
00285 }
00286
00287 LOG("lstn");
00288 if (listen(socket_server_fd, 1)) {
00289 LOG("listen err %d", errno);
00290 return;
00291 }
00292
00293 LOG("cthd");
00294 pthread_t thd;
00295 int err = pthread_create(&thd, NULL, thread_touch_socket_server, (void*)socket_server_fd);
00296 if (err) {
00297 LOG("pthread_create err %d", err);
00298 return;
00299 }
00300 }
00301 }
00302
00303 #if (ANDROID_VER>=400)
00304 static ScreenshotClient screenshot;
00305 #if (ANDROID_VER>=420)
00306 static sp<IBinder> display;
00307 #endif
00308 #else
00309 static int fb;
00310 static char* mapbase;
00311 static size_t lastMapSize;
00312 #endif
00313
00314 extern "C" void asc_capture(ASC* asc) {
00315 int err, width, height, internal_width, bytesPerPixel, rawImageSize;
00316
00317 if (isFirstTime) {
00318 chkDev();
00319 #if (ANDROID_VER>=400)
00320 #if (ANDROID_VER>=420)
00321 ProcessState::self()->startThreadPool();
00322 display = SurfaceComposerClient::getBuiltInDisplay(0 );
00323 if (display==NULL) ABORT("gbd e");
00324 #endif
00325 #else
00326 LOG("o f");
00327 fb = open("/dev/graphics/fb0", O_RDONLY);
00328 if (fb < 0) ABORT_ERRNO("o f");
00329 mapbase = NULL;
00330 lastMapSize = 0;
00331 #endif
00332
00333
00334 if (isatty(STDOUT_FILENO)) {
00335 LOG("iaty");
00336 struct termios term;
00337 if (tcgetattr(STDOUT_FILENO, &term)) ABORT_ERRNO("tga");
00338 LOG("mkr");
00339 cfmakeraw(&term);
00340 LOG("tsa");
00341 if (tcsetattr(STDOUT_FILENO, TCSANOW, &term)) ABORT_ERRNO("tsa");
00342 }
00343
00344 create_cmd_socket_server();
00345 create_touch_socket_server();
00346 }
00347
00348 if (isPaused && !isFirstTime) {
00349 AutoMutex autoLock(mutex);
00350 if (isPaused && !isFirstTime) {
00351 if (blackscreen==NULL) {
00352 asc->data = blackscreen = (char*)malloc(asc->size);
00353 if (!blackscreen) ABORT("oom");
00354 memset(blackscreen, isScreenOff ? 0 : 0x40, asc->size);
00355 LOG("use blackscreen");
00356 return;
00357 }
00358 else {
00359 if (blackscreen_extra_count++ < 3) {
00360 asc->data = blackscreen;
00361 LOG("use blackscreen");
00362 return;
00363 }
00364 blackscreen_extra_count = 0;
00365 free(blackscreen);
00366 blackscreen = NULL;
00367
00368 do {
00369 LOG("wait for resume");
00370 cond.wait(mutex);
00371 } while ( isPaused );
00372 }
00373 }
00374 }
00375
00376 #if (ANDROID_VER>=400)
00377 LOG("c w %d h %d", asc->w, asc->h);
00378 for(;;) {
00379 #if (ANDROID_VER>=500)
00380 err = screenshot.update(display, Rect(), asc->w, asc->h, false);
00381 #elif (ANDROID_VER>=420)
00382 err = screenshot.update(display, asc->w, asc->h);
00383 #else
00384 err = screenshot.update(asc->w, asc->h);
00385 #endif
00386 if(err) {
00387 LOGI("c e %d", err);
00388 usleep(250*1000);
00389 if (!isFirstTime) {
00390 if (!blackscreen) {
00391 blackscreen = (char*)malloc(asc->size);
00392 if (!blackscreen) ABORT("oom");
00393 }
00394 memset(blackscreen, 0x80, asc->size);
00395 asc->data = blackscreen;
00396 return;
00397 }
00398 } else {
00399 if (blackscreen) {
00400 free(blackscreen);
00401 blackscreen = NULL;
00402 }
00403 break;
00404 }
00405 }
00406
00407 rawImageSize = screenshot.getSize();
00408 width = screenshot.getWidth();
00409 height = screenshot.getHeight();
00410 internal_width = screenshot.getStride();
00411 bytesPerPixel = rawImageSize/internal_width/height;
00412
00413 if (isFirstTime) {
00414 strncpy(asc->pixfmtName,
00415 (bytesPerPixel==4) ? "rgb0" :
00416 (bytesPerPixel==3) ? "rgb24" :
00417 (bytesPerPixel==2) ? "rgb565le" :
00418 (bytesPerPixel==5) ? "rgb48le" :
00419 (bytesPerPixel==6) ? "rgba64le" :
00420 (LOG("s bbp %d", bytesPerPixel),"unknown"),
00421 sizeof(asc->pixfmtName)-1);
00422
00423 LOG("c r %s is %d w %d h %d bbp %d iw %d f %d",
00424 asc->pixfmtName, width*height*bytesPerPixel, width, height, bytesPerPixel, internal_width, screenshot.getFormat());
00425 }
00426
00427 asc->data = (char*)screenshot.getPixels();
00428
00429 if (internal_width > width) {
00430 char* p1 = asc->data;
00431 char* p2 = asc->data;
00432 int size1 = width*bytesPerPixel;
00433 int size2 = internal_width*bytesPerPixel;
00434 for (int h=0; h < height; h++, p2 += size2, p1+= size1)
00435 memmove(p1, p2, size1);
00436 }
00437 #else
00438 LOG("ic gv");
00439 struct fb_var_screeninfo vinfo;
00440 if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) ABORT_ERRNO("ic gv");
00441
00442 width = vinfo.xres;
00443 height = vinfo.yres;
00444 internal_width = width;
00445 bytesPerPixel = vinfo.bits_per_pixel/8;
00446 rawImageSize = (width*height) * bytesPerPixel;
00447
00448 if (isFirstTime) {
00449 if (vinfo.transp.offset==0&&vinfo.bits_per_pixel==32&&vinfo.red.offset==8) strncpy(asc->pixfmtName,"0rgb", sizeof(asc->pixfmtName)-1);
00450 else if (vinfo.transp.offset==0&&vinfo.bits_per_pixel==32&&vinfo.red.offset==24) strncpy(asc->pixfmtName,"0bgr", sizeof(asc->pixfmtName)-1);
00451 else
00452 strncpy(asc->pixfmtName,
00453 (vinfo.bits_per_pixel==32&&vinfo.red.offset==0) ? "rgb0" :
00454 (vinfo.bits_per_pixel==32&&vinfo.red.offset!=0) ? "bgr0" :
00455 (vinfo.bits_per_pixel==24&&vinfo.red.offset==0) ? "rgb24" :
00456 (vinfo.bits_per_pixel==24&&vinfo.red.offset!=0) ? "bgr24" :
00457 (vinfo.bits_per_pixel==16&&vinfo.red.offset==0) ? "rgb565le" :
00458 (vinfo.bits_per_pixel==16&&vinfo.red.offset!=0) ? "bgr565le" :
00459 (vinfo.bits_per_pixel==48&&vinfo.red.offset==0) ? "rgb48le" :
00460 (vinfo.bits_per_pixel==48&&vinfo.red.offset!=0) ? "bgr48le" :
00461 (vinfo.bits_per_pixel==64&&vinfo.red.offset==0) ? "rgba64le" :
00462 (vinfo.bits_per_pixel==64&&vinfo.red.offset!=0) ? "bgra64le" :
00463 (LOG("strange bits_per_pixel:%d", vinfo.bits_per_pixel),"unknown"),
00464 sizeof(asc->pixfmtName)-1);
00465
00466 LOG("gv r %s is %d w %d h %d bpp %d vw %d vh %d"
00467 " bits:%d"
00468 " R:(offset:%d length:%d msb_right:%d)"
00469 " G:(offset:%d length:%d msb_right:%d)"
00470 " B:(offset:%d length:%d msb_right:%d)"
00471 " A:(offset:%d length:%d msb_right:%d)"
00472 " grayscale:%d nonstd:%d rotate:%d",
00473 asc->pixfmtName, rawImageSize, width, height, bytesPerPixel, vinfo.xres_virtual, vinfo.yres_virtual
00474 ,vinfo.bits_per_pixel
00475 ,vinfo.red.offset, vinfo.red.length, vinfo.red.msb_right
00476 ,vinfo.green.offset, vinfo.green.length, vinfo.green.msb_right
00477 ,vinfo.blue.offset, vinfo.blue.length, vinfo.blue.msb_right
00478 ,vinfo.transp.offset, vinfo.transp.length, vinfo.transp.msb_right
00479 ,vinfo.grayscale, vinfo.nonstd, vinfo.rotate );
00480 }
00481
00482 uint32_t offset = (vinfo.xoffset + vinfo.yoffset*width) *bytesPerPixel;
00483 int virtualSize = vinfo.xres_virtual*vinfo.yres_virtual*bytesPerPixel;
00484 if (offset+rawImageSize > virtualSize) {
00485 LOG("Strange! offset:%d+rawImageSize:%d > virtualSize:%d", offset, rawImageSize, virtualSize);
00486 virtualSize = offset+rawImageSize;
00487 }
00488
00489 if (virtualSize > lastMapSize) {
00490 if (mapbase) {
00491 LOG("remap due to virtualSize %d is bigger than previous %d", virtualSize, lastMapSize);
00492 munmap(mapbase, lastMapSize);
00493 mapbase = NULL;
00494 }
00495 lastMapSize = virtualSize;
00496 }
00497
00498 if (mapbase==NULL) {
00499 mapbase = (char*)mmap(0, virtualSize, PROT_READ, MAP_PRIVATE, fb, 0);
00500 if (mapbase==NULL) ABORT_ERRNO("mmap %d", virtualSize);
00501 }
00502
00503 asc->data = mapbase + offset;
00504 #endif
00505
00506 if (isFirstTime) {
00507 asc->w = width;
00508 asc->h = height;
00509 asc->size = width*height*bytesPerPixel;
00510 if (isPaused) {
00511 asc->data = blackscreen = (char*)calloc(asc->size, 1);
00512 if (!blackscreen) ABORT("oom");
00513 memset(blackscreen, isScreenOff ? 0 : 0x40, asc->size);
00514 LOG("use blackscreen");
00515 }
00516
00517 if (! (getenv("ASC_LOG_ALL") && atoi(getenv("ASC_LOG_ALL")) > 0) )
00518 needLog = false;
00519 isFirstTime = false;
00520 }
00521 }
00522
00523 #if MAKE_TEST==1
00524 extern "C" int main(int argc, char** argv) {
00525 ASC asc;
00526 memset(&asc, 0, sizeof(ASC));
00527 asc.width = argc>1 && atoi(argv[1])> 0 ? atoi(argv[1]) : 0;
00528 asc.height = argc>2 && atoi(argv[2])> 0 ? atoi(argv[2]) : 0;
00529
00530 for(;;) {
00531 asc_capture(&asc);
00532 static int64_t seq = 0;
00533 LOG("o i %lld", ++seq);
00534 write(1, asc.data, asc.size);
00535 }
00536 }
00537 #endif