127e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler#include <stdlib.h> 227e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler#include <stdio.h> 327e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler#include <unistd.h> 427e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler#include <string.h> 527e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler#include <fcntl.h> 627e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler#include <errno.h> 727e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 827e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler#include <linux/fb.h> 927e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 1027e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler#include <zlib.h> 1127e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler#include <libpng/png.h> 1227e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 1327e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler#include "private/android_filesystem_config.h" 1427e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 1527e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler#define LOG_TAG "screenshot" 1627e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler#include <utils/Log.h> 1727e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 1827e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandlervoid take_screenshot(FILE *fb_in, FILE *fb_out) { 1927e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler int fb; 2027e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler char imgbuf[0x10000]; 2127e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler struct fb_var_screeninfo vinfo; 2227e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler png_structp png; 2327e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler png_infop info; 2427e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler unsigned int r,c,rowlen; 2527e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler unsigned int bytespp,offset; 2627e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 2727e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler fb = fileno(fb_in); 2827e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler if(fb < 0) { 293762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("failed to open framebuffer\n"); 3027e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler return; 3127e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler } 3227e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler fb_in = fdopen(fb, "r"); 3327e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 3427e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) { 353762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("failed to get framebuffer info\n"); 3627e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler return; 3727e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler } 3827e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler fcntl(fb, F_SETFD, FD_CLOEXEC); 3927e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 4027e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 4127e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler if (png == NULL) { 423762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("failed png_create_write_struct\n"); 4327e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler fclose(fb_in); 4427e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler return; 4527e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler } 4627e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 4727e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler png_init_io(png, fb_out); 4827e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler info = png_create_info_struct(png); 4927e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler if (info == NULL) { 503762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("failed png_create_info_struct\n"); 5127e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler png_destroy_write_struct(&png, NULL); 5227e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler fclose(fb_in); 5327e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler return; 5427e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler } 5527e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler if (setjmp(png_jmpbuf(png))) { 563762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("failed png setjmp\n"); 5727e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler png_destroy_write_struct(&png, NULL); 5827e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler fclose(fb_in); 5927e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler return; 6027e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler } 6127e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 6227e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler bytespp = vinfo.bits_per_pixel / 8; 6327e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler png_set_IHDR(png, info, 6427e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler vinfo.xres, vinfo.yres, vinfo.bits_per_pixel / 4, 6527e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, 6627e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 6727e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler png_write_info(png, info); 6827e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 6927e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler rowlen=vinfo.xres * bytespp; 7027e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler if (rowlen > sizeof(imgbuf)) { 713762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("crazy rowlen: %d\n", rowlen); 7227e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler png_destroy_write_struct(&png, NULL); 7327e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler fclose(fb_in); 7427e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler return; 7527e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler } 7627e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 7727e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler offset = vinfo.xoffset * bytespp + vinfo.xres * vinfo.yoffset * bytespp; 7827e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler fseek(fb_in, offset, SEEK_SET); 7927e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 8027e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler for(r=0; r<vinfo.yres; r++) { 8127e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler int len = fread(imgbuf, 1, rowlen, fb_in); 8227e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler if (len <= 0) break; 8327e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler png_write_row(png, (png_bytep)imgbuf); 8427e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler } 8527e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 8627e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler png_write_end(png, info); 8727e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler fclose(fb_in); 8827e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler png_destroy_write_struct(&png, NULL); 8927e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler} 9027e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 91e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandlervoid fork_sound(const char* path) { 92e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler pid_t pid = fork(); 93e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler if (pid == 0) { 94e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler execl("/system/bin/stagefright", "stagefright", "-o", "-a", path, NULL); 95e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler } 96e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler} 97e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler 98e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandlervoid usage() { 99e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler fprintf(stderr, 100e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler "usage: screenshot [-s soundfile] filename.png\n" 101e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler " -s: play a sound effect to signal success\n" 102e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler " -i: autoincrement to avoid overwriting filename.png\n" 103e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler ); 104e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler} 105e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler 10627e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandlerint main(int argc, char**argv) { 10727e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler FILE *png = NULL; 10827e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler FILE *fb_in = NULL; 109e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler char outfile[PATH_MAX] = ""; 110e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler 111e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler char * soundfile = NULL; 112e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler int do_increment = 0; 113e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler 114e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler int c; 115e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler while ((c = getopt(argc, argv, "s:i")) != -1) { 116e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler switch (c) { 117e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler case 's': soundfile = optarg; break; 118e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler case 'i': do_increment = 1; break; 119e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler case '?': 120e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler case 'h': 121e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler usage(); exit(1); 122e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler } 12327e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler } 124e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler argc -= optind; 125e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler argv += optind; 126e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler 127e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler if (argc < 1) { 128e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler usage(); exit(1); 129e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler } 130e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler 131e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler strlcpy(outfile, argv[0], PATH_MAX); 132e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler if (do_increment) { 133e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler struct stat st; 134e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler char base[PATH_MAX] = ""; 135e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler int i = 0; 136e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler while (stat(outfile, &st) == 0) { 137e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler if (!base[0]) { 138e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler char *p = strrchr(outfile, '.'); 139e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler if (p) *p = '\0'; 140e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler strcpy(base, outfile); 141e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler } 142e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler snprintf(outfile, PATH_MAX, "%s-%d.png", base, ++i); 143e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler } 144e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler } 145e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler 14627e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler fb_in = fopen("/dev/graphics/fb0", "r"); 14727e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler if (!fb_in) { 14827e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler fprintf(stderr, "error: could not read framebuffer\n"); 14927e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler exit(1); 15027e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler } 15127e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 15227e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler /* switch to non-root user and group */ 15327e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler gid_t groups[] = { AID_LOG, AID_SDCARD_RW }; 15427e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler setgroups(sizeof(groups)/sizeof(groups[0]), groups); 15527e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler setuid(AID_SHELL); 15627e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 157e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler png = fopen(outfile, "w"); 15827e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler if (!png) { 159e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler fprintf(stderr, "error: writing file %s: %s\n", 160e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler outfile, strerror(errno)); 16127e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler exit(1); 16227e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler } 16327e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 16427e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler take_screenshot(fb_in, png); 16527e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler 166e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler if (soundfile) { 167e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler fork_sound(soundfile); 168e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler } 169e9ddcba348ee45fe000d84efaad98484db032926Daniel Sandler 17027e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler exit(0); 17127e1a79bf7622f43803ca7e4635b1ac90b44b9bdDaniel Sandler} 172