194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <stdlib.h> 294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <stdio.h> 394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <unistd.h> 494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <string.h> 594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <fcntl.h> 694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <errno.h> 794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <linux/fb.h> 994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 1094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <zlib.h> 1194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <libpng/png.h> 1294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 1394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include "private/android_filesystem_config.h" 1494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 1594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#define LOG_TAG "screenshot" 1694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <utils/Log.h> 1794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 1894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodvoid take_screenshot(FILE *fb_in, FILE *fb_out) { 1994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int fb; 2094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood char imgbuf[0x10000]; 2194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood struct fb_var_screeninfo vinfo; 2294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood png_structp png; 2394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood png_infop info; 2494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood unsigned int r,c,rowlen; 2594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood unsigned int bytespp,offset; 2694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 2794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fb = fileno(fb_in); 2894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if(fb < 0) { 2994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("failed to open framebuffer\n"); 3094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return; 3194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 3294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fb_in = fdopen(fb, "r"); 3394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 3494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) { 3594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("failed to get framebuffer info\n"); 3694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return; 3794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 3894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fcntl(fb, F_SETFD, FD_CLOEXEC); 3994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 4094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 4194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (png == NULL) { 4294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("failed png_create_write_struct\n"); 4394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fclose(fb_in); 4494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return; 4594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 4694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 4794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood png_init_io(png, fb_out); 4894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood info = png_create_info_struct(png); 4994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (info == NULL) { 5094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("failed png_create_info_struct\n"); 5194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood png_destroy_write_struct(&png, NULL); 5294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fclose(fb_in); 5394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return; 5494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 5594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (setjmp(png_jmpbuf(png))) { 5694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("failed png setjmp\n"); 5794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood png_destroy_write_struct(&png, NULL); 5894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fclose(fb_in); 5994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return; 6094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 6194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 6294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood bytespp = vinfo.bits_per_pixel / 8; 6394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood png_set_IHDR(png, info, 6494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood vinfo.xres, vinfo.yres, vinfo.bits_per_pixel / 4, 6594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, 6694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 6794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood png_write_info(png, info); 6894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 6994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood rowlen=vinfo.xres * bytespp; 7094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (rowlen > sizeof(imgbuf)) { 7194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ALOGE("crazy rowlen: %d\n", rowlen); 7294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood png_destroy_write_struct(&png, NULL); 7394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fclose(fb_in); 7494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood return; 7594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 7694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 7794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood offset = vinfo.xoffset * bytespp + vinfo.xres * vinfo.yoffset * bytespp; 7894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fseek(fb_in, offset, SEEK_SET); 7994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 8094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood for(r=0; r<vinfo.yres; r++) { 8194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int len = fread(imgbuf, 1, rowlen, fb_in); 8294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (len <= 0) break; 8394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood png_write_row(png, (png_bytep)imgbuf); 8494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 8594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 8694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood png_write_end(png, info); 8794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fclose(fb_in); 8894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood png_destroy_write_struct(&png, NULL); 8994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 9094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 9194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodvoid fork_sound(const char* path) { 9294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood pid_t pid = fork(); 9394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (pid == 0) { 9494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood execl("/system/bin/stagefright", "stagefright", "-o", "-a", path, NULL); 9594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 9694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 9794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 9894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodvoid usage() { 9994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fprintf(stderr, 10094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood "usage: screenshot [-s soundfile] filename.png\n" 10194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood " -s: play a sound effect to signal success\n" 10294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood " -i: autoincrement to avoid overwriting filename.png\n" 10394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood ); 10494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 10594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 10694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodint main(int argc, char**argv) { 10794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood FILE *png = NULL; 10894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood FILE *fb_in = NULL; 10994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood char outfile[PATH_MAX] = ""; 11094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 11194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood char * soundfile = NULL; 11294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int do_increment = 0; 11394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 11494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int c; 11594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood while ((c = getopt(argc, argv, "s:i")) != -1) { 11694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood switch (c) { 11794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood case 's': soundfile = optarg; break; 11894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood case 'i': do_increment = 1; break; 11994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood case '?': 12094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood case 'h': 12194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood usage(); exit(1); 12294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 12394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 12494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood argc -= optind; 12594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood argv += optind; 12694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 12794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (argc < 1) { 12894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood usage(); exit(1); 12994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 13094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 13194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood strlcpy(outfile, argv[0], PATH_MAX); 13294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (do_increment) { 13394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood struct stat st; 13494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood char base[PATH_MAX] = ""; 13594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood int i = 0; 13694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood while (stat(outfile, &st) == 0) { 13794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (!base[0]) { 13894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood char *p = strrchr(outfile, '.'); 13994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (p) *p = '\0'; 14094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood strcpy(base, outfile); 14194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 14294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood snprintf(outfile, PATH_MAX, "%s-%d.png", base, ++i); 14394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 14494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 14594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 14694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fb_in = fopen("/dev/graphics/fb0", "r"); 14794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (!fb_in) { 14894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fprintf(stderr, "error: could not read framebuffer\n"); 14994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood exit(1); 15094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 15194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 15294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood /* switch to non-root user and group */ 15394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood gid_t groups[] = { AID_LOG, AID_SDCARD_RW }; 15494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood setgroups(sizeof(groups)/sizeof(groups[0]), groups); 15594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood setuid(AID_SHELL); 15694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 15794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood png = fopen(outfile, "w"); 15894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (!png) { 15994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fprintf(stderr, "error: writing file %s: %s\n", 16094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood outfile, strerror(errno)); 16194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood exit(1); 16294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 16394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 16494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood take_screenshot(fb_in, png); 16594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 16694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood if (soundfile) { 16794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood fork_sound(soundfile); 16894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood } 16994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood 17094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood exit(0); 17194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} 172