diff options
Diffstat (limited to 'cmds')
-rw-r--r-- | cmds/am/src/com/android/commands/am/Am.java | 34 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.c | 45 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.h | 3 | ||||
-rw-r--r-- | cmds/dumpstate/utils.c | 4 | ||||
-rw-r--r-- | cmds/screenshot/Android.mk | 16 | ||||
-rw-r--r-- | cmds/screenshot/screenshot.c | 171 |
6 files changed, 264 insertions, 9 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 301883f..4265cc5 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -98,6 +98,8 @@ public class Am { sendBroadcast(); } else if (op.equals("profile")) { runProfile(); + } else if (op.equals("dumpheap")) { + runDumpHeap(); } else { throw new IllegalArgumentException("Unknown command: " + op); } @@ -140,6 +142,11 @@ public class Am { String value = nextArgRequired(); intent.putExtra(key, Integer.valueOf(value)); hasIntentInfo = true; + } else if (opt.equals("--el")) { + String key = nextArgRequired(); + String value = nextArgRequired(); + intent.putExtra(key, Long.valueOf(value)); + hasIntentInfo = true; } else if (opt.equals("--ez")) { String key = nextArgRequired(); String value = nextArgRequired(); @@ -424,6 +431,28 @@ public class Am { } } + private void runDumpHeap() throws Exception { + boolean managed = !"-n".equals(nextOption()); + String process = nextArgRequired(); + String heapFile = nextArgRequired(); + ParcelFileDescriptor fd = null; + + try { + fd = ParcelFileDescriptor.open( + new File(heapFile), + ParcelFileDescriptor.MODE_CREATE | + ParcelFileDescriptor.MODE_TRUNCATE | + ParcelFileDescriptor.MODE_READ_WRITE); + } catch (FileNotFoundException e) { + System.err.println("Error: Unable to open file: " + heapFile); + return; + } + + if (!mAm.dumpHeap(process, managed, heapFile, fd)) { + throw new AndroidException("HEAP DUMP FAILED on process " + process); + } + } + private class IntentReceiver extends IIntentReceiver.Stub { private boolean mFinished = false; @@ -593,6 +622,8 @@ public class Am { "\n" + " start profiling: am profile <PROCESS> start <FILE>\n" + " stop profiling: am profile <PROCESS> stop\n" + + " dump heap: am dumpheap [flags] <PROCESS> <FILE>\n" + + " -n: dump native heap instead of managed heap\n" + "\n" + " <INTENT> specifications include these flags:\n" + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + @@ -600,7 +631,8 @@ public class Am { " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" + " [--esn <EXTRA_KEY> ...]\n" + " [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" + - " [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" + + " [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" + + " [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" + " [-n <COMPONENT>] [-f <FLAGS>]\n" + " [--grant-read-uri-permission] [--grant-write-uri-permission]\n" + " [--debug-log-resolution]\n" + diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index 082e704..267a9a7 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 @@ static void dumpstate() { 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 */ @@ -103,7 +111,12 @@ static void dumpstate() { dump_file("NETWORK ROUTES", "/proc/net/route"); dump_file("ARP CACHE", "/proc/net/arp"); + run_command("WIFI NETWORKS", 20, + "su", "root", "wpa_cli", "list_networks", NULL); + #ifdef FWDUMP_bcm4329 + run_command("DUMP WIFI STATUS", 20, + "su", "root", "dhdutil", "-i", "eth0", "dump", NULL); run_command("DUMP WIFI FIRMWARE LOG", 60, "su", "root", "dhdutil", "-i", "eth0", "upload", "/data/local/tmp/wlan_crash.dump", NULL); #endif @@ -164,18 +177,25 @@ static void dumpstate() { } static void usage() { - fprintf(stderr, "usage: dumpstate [-d] [-o file] [-s] [-z]\n" - " -d: append date to filename (requires -o)\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[]) { int do_add_date = 0; int do_compress = 0; char* use_outfile = 0; + char* begin_sound = 0; + char* end_sound = 0; int use_socket = 0; + int do_fb = 0; LOGI("begin\n"); @@ -191,13 +211,16 @@ int main(int argc, char *argv[]) { dump_traces_path = dump_vm_traces(); int c; - while ((c = getopt(argc, argv, "dho: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; + case 'e': end_sound = optarg; break; case 'o': use_outfile = optarg; break; 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(); @@ -234,6 +257,10 @@ int main(int argc, char *argv[]) { 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)); @@ -241,16 +268,18 @@ int main(int argc, char *argv[]) { gzip_pid = redirect_to_file(stdout, tmp_path, do_compress); } - /* bzzzzzz */ - if (vibrator) { + if (begin_sound) { + play_sound(begin_sound); + } else if (vibrator) { fputs("150", vibrator); fflush(vibrator); } dumpstate(); - /* bzzz bzzz bzzz */ - if (vibrator) { + if (end_sound) { + play_sound(end_sound); + } else if (vibrator) { int i; for (i = 0; i < 3; i++) { fputs("75\n", vibrator); diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 682eafd..83b1d11 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -44,4 +44,7 @@ void for_each_pid(void (*func)(int, const char *), const char *header); /* Displays a blocked processes in-kernel wait channel */ void show_wchan(int pid, const char *name); +/* Play a sound via Stagefright */ +void play_sound(const char* path); + #endif /* _DUMPSTATE_H_ */ diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c index c7a78cc..f92acbb 100644 --- a/cmds/dumpstate/utils.c +++ b/cmds/dumpstate/utils.c @@ -429,3 +429,7 @@ const char *dump_vm_traces() { rename(anr_traces_path, traces_path); return dump_traces_path; } + +void play_sound(const char* path) { + run_command(NULL, 5, "/system/bin/stagefright", "-o", "-a", path, NULL); +} diff --git a/cmds/screenshot/Android.mk b/cmds/screenshot/Android.mk new file mode 100644 index 0000000..99c7aeb --- /dev/null +++ b/cmds/screenshot/Android.mk @@ -0,0 +1,16 @@ +ifneq ($(TARGET_SIMULATOR),true) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := screenshot.c + +LOCAL_MODULE := screenshot + +LOCAL_SHARED_LIBRARIES := libcutils libz +LOCAL_STATIC_LIBRARIES := libpng +LOCAL_C_INCLUDES += external/zlib + +include $(BUILD_EXECUTABLE) + +endif diff --git a/cmds/screenshot/screenshot.c b/cmds/screenshot/screenshot.c new file mode 100644 index 0000000..048636c --- /dev/null +++ b/cmds/screenshot/screenshot.c @@ -0,0 +1,171 @@ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <linux/fb.h> + +#include <zlib.h> +#include <libpng/png.h> + +#include "private/android_filesystem_config.h" + +#define LOG_TAG "screenshot" +#include <utils/Log.h> + +void take_screenshot(FILE *fb_in, FILE *fb_out) { + int fb; + char imgbuf[0x10000]; + struct fb_var_screeninfo vinfo; + png_structp png; + png_infop info; + unsigned int r,c,rowlen; + unsigned int bytespp,offset; + + fb = fileno(fb_in); + if(fb < 0) { + LOGE("failed to open framebuffer\n"); + return; + } + fb_in = fdopen(fb, "r"); + + if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) { + LOGE("failed to get framebuffer info\n"); + return; + } + fcntl(fb, F_SETFD, FD_CLOEXEC); + + png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png == NULL) { + LOGE("failed png_create_write_struct\n"); + fclose(fb_in); + return; + } + + png_init_io(png, fb_out); + info = png_create_info_struct(png); + if (info == NULL) { + LOGE("failed png_create_info_struct\n"); + png_destroy_write_struct(&png, NULL); + fclose(fb_in); + return; + } + if (setjmp(png_jmpbuf(png))) { + LOGE("failed png setjmp\n"); + png_destroy_write_struct(&png, NULL); + fclose(fb_in); + return; + } + + bytespp = vinfo.bits_per_pixel / 8; + png_set_IHDR(png, info, + vinfo.xres, vinfo.yres, vinfo.bits_per_pixel / 4, + PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + png_write_info(png, info); + + rowlen=vinfo.xres * bytespp; + if (rowlen > sizeof(imgbuf)) { + LOGE("crazy rowlen: %d\n", rowlen); + png_destroy_write_struct(&png, NULL); + fclose(fb_in); + return; + } + + offset = vinfo.xoffset * bytespp + vinfo.xres * vinfo.yoffset * bytespp; + fseek(fb_in, offset, SEEK_SET); + + for(r=0; r<vinfo.yres; r++) { + int len = fread(imgbuf, 1, rowlen, fb_in); + if (len <= 0) break; + png_write_row(png, (png_bytep)imgbuf); + } + + png_write_end(png, info); + fclose(fb_in); + png_destroy_write_struct(&png, NULL); +} + +void fork_sound(const char* path) { + pid_t pid = fork(); + if (pid == 0) { + execl("/system/bin/stagefright", "stagefright", "-o", "-a", path, NULL); + } +} + +void usage() { + fprintf(stderr, + "usage: screenshot [-s soundfile] filename.png\n" + " -s: play a sound effect to signal success\n" + " -i: autoincrement to avoid overwriting filename.png\n" + ); +} + +int main(int argc, char**argv) { + FILE *png = NULL; + FILE *fb_in = NULL; + char outfile[PATH_MAX] = ""; + + char * soundfile = NULL; + int do_increment = 0; + + int c; + while ((c = getopt(argc, argv, "s:i")) != -1) { + switch (c) { + case 's': soundfile = optarg; break; + case 'i': do_increment = 1; break; + case '?': + case 'h': + usage(); exit(1); + } + } + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(); exit(1); + } + + strlcpy(outfile, argv[0], PATH_MAX); + if (do_increment) { + struct stat st; + char base[PATH_MAX] = ""; + int i = 0; + while (stat(outfile, &st) == 0) { + if (!base[0]) { + char *p = strrchr(outfile, '.'); + if (p) *p = '\0'; + strcpy(base, outfile); + } + snprintf(outfile, PATH_MAX, "%s-%d.png", base, ++i); + } + } + + fb_in = fopen("/dev/graphics/fb0", "r"); + if (!fb_in) { + fprintf(stderr, "error: could not read framebuffer\n"); + exit(1); + } + + /* switch to non-root user and group */ + gid_t groups[] = { AID_LOG, AID_SDCARD_RW }; + setgroups(sizeof(groups)/sizeof(groups[0]), groups); + setuid(AID_SHELL); + + png = fopen(outfile, "w"); + if (!png) { + fprintf(stderr, "error: writing file %s: %s\n", + outfile, strerror(errno)); + exit(1); + } + + take_screenshot(fb_in, png); + + if (soundfile) { + fork_sound(soundfile); + } + + exit(0); +} |