On-device screenshot support.
This comes in the form of a command, `screenshot`, which
will read /dev/graphics/fb0 (in a manner very similar to
adb's framebuffer_service) and write to the specified PNG
file.
Additionally, dumpstate now accepts a -p flag (mnemonic:
"picture" or "png") that, when specified, will cause a
screenshot to be captured in the same directory as the
bugreport.
Future work: invoke `dumpstate -p` when the bugreport
keychord is pressed, giving users a convenient way to attach
screenshots to bug reports (or simply take screenshots at
all without developer tools).
Bug: 2216571 (and probably plenty of others)
Change-Id: I36afbc55a0308a7bc01112ef39c4c62777efb203
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 02c9cbc..8f3642c 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -39,6 +39,8 @@
static char cmdline_buf[16384] = "(unknown)";
static const char *dump_traces_path = NULL;
+static char screenshot_path[PATH_MAX] = "";
+
/* dumps the current system state to stdout */
static void dumpstate() {
time_t now = time(NULL);
@@ -76,6 +78,12 @@
dump_file("SLAB INFO", "/proc/slabinfo");
dump_file("ZONEINFO", "/proc/zoneinfo");
+ if (screenshot_path[0]) {
+ LOGI("taking screenshot\n");
+ run_command(NULL, 5, "su", "root", "screenshot", screenshot_path, NULL);
+ LOGI("wrote screenshot: %s\n", screenshot_path);
+ }
+
run_command("SYSTEM LOG", 20, "logcat", "-v", "time", "-d", "*:v", NULL);
/* show the traces we collected in main(), if that was done */
@@ -167,14 +175,15 @@
}
static void usage() {
- fprintf(stderr, "usage: dumpstate [-b file] [-d] [-e file] [-o file] [-s] "
- "[-z]\n"
- " -b: play sound file instead of vibrate, at beginning of job\n"
- " -d: append date to filename (requires -o)\n"
- " -e: play sound file instead of vibrate, at end of job\n"
+ fprintf(stderr, "usage: dumpstate [-b soundfile] [-e soundfile] [-o file [-d] [-p] [-z]] [-s]\n"
" -o: write to file (instead of stdout)\n"
+ " -d: append date to filename (requires -o)\n"
+ " -z: gzip output (requires -o)\n"
+ " -p: capture screenshot to filename.png (requires -o)\n"
" -s: write output to control socket (for init)\n"
- " -z: gzip output (requires -o)\n");
+ " -b: play sound file instead of vibrate, at beginning of job\n"
+ " -e: play sound file instead of vibrate, at end of job\n"
+ );
}
int main(int argc, char *argv[]) {
@@ -184,6 +193,7 @@
char* begin_sound = 0;
char* end_sound = 0;
int use_socket = 0;
+ int do_fb = 0;
LOGI("begin\n");
@@ -199,7 +209,7 @@
dump_traces_path = dump_vm_traces();
int c;
- while ((c = getopt(argc, argv, "b:de:ho:svz")) != -1) {
+ while ((c = getopt(argc, argv, "b:de:ho:svzp")) != -1) {
switch (c) {
case 'b': begin_sound = optarg; break;
case 'd': do_add_date = 1; break;
@@ -208,6 +218,7 @@
case 's': use_socket = 1; break;
case 'v': break; // compatibility no-op
case 'z': do_compress = 6; break;
+ case 'p': do_fb = 1; break;
case '?': printf("\n");
case 'h':
usage();
@@ -244,6 +255,10 @@
strftime(date, sizeof(date), "-%Y-%m-%d-%H-%M-%S", localtime(&now));
strlcat(path, date, sizeof(path));
}
+ if (do_fb) {
+ strlcpy(screenshot_path, path, sizeof(screenshot_path));
+ strlcat(screenshot_path, ".png", sizeof(screenshot_path));
+ }
strlcat(path, ".txt", sizeof(path));
if (do_compress) strlcat(path, ".gz", sizeof(path));
strlcpy(tmp_path, path, sizeof(tmp_path));