auto import from //depot/cupcake/@135843
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
new file mode 100644
index 0000000..e08230f
--- /dev/null
+++ b/cmds/dumpstate/dumpstate.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include "private/android_filesystem_config.h"
+
+#include "dumpstate.h"
+
+static char* const gzip_args[] = { "gzip", "-6", 0 };
+static int start_pattern[] = { 150, 0 };
+static int end_pattern[] = { 75, 50, 75, 50, 75, 0 };
+
+static struct tm now;
+
+/* dumps the current system state to stdout */
+static void dumpstate(int full) {
+ if (full) {
+ PRINT("========================================================");
+ PRINT("== dumpstate");
+ PRINT("========================================================");
+ PRINT("------ MEMORY INFO ------");
+ DUMP("/proc/meminfo");
+ PRINT("------ CPU INFO ------");
+ EXEC7("top", "-n", "1", "-d", "1", "-m", "30", "-t");
+ PRINT("------ PROCRANK ------");
+ EXEC_XBIN("procrank");
+ PRINT("------ VIRTUAL MEMORY STATS ------");
+ DUMP("/proc/vmstat");
+ PRINT("------ SLAB INFO ------");
+ DUMP("/proc/slabinfo");
+ PRINT("------ ZONEINFO ------");
+ DUMP("/proc/zoneinfo");
+ PRINT("------ SYSTEM LOG ------");
+ EXEC4("logcat", "-v", "time", "-d", "*:v");
+ PRINT("------ VM TRACES ------");
+ DUMP("/data/anr/traces.txt");
+ PRINT("------ EVENT LOG TAGS ------");
+ DUMP("/etc/event-log-tags");
+ PRINT("------ EVENT LOG ------");
+ EXEC6("logcat", "-b", "events", "-v", "time", "-d", "*:v");
+ PRINT("------ RADIO LOG ------");
+ EXEC6("logcat", "-b", "radio", "-v", "time", "-d", "*:v");
+ PRINT("------ NETWORK STATE ------");
+ PRINT("Interfaces:");
+ EXEC("netcfg");
+ PRINT("");
+ PRINT("Routes:");
+ DUMP("/proc/net/route");
+ PRINT("------ SYSTEM PROPERTIES ------");
+ print_properties();
+ PRINT("------ KERNEL LOG ------");
+ EXEC("dmesg");
+ PRINT("------ KERNEL WAKELOCKS ------");
+ DUMP("/proc/wakelocks");
+ PRINT("");
+ PRINT("------ PROCESSES ------");
+ EXEC("ps");
+ PRINT("------ PROCESSES AND THREADS ------");
+ EXEC2("ps", "-t", "-p");
+ PRINT("------ LIBRANK ------");
+ EXEC_XBIN("librank");
+ PRINT("------ BINDER FAILED TRANSACTION LOG ------");
+ DUMP("/proc/binder/failed_transaction_log");
+ PRINT("");
+ PRINT("------ BINDER TRANSACTION LOG ------");
+ DUMP("/proc/binder/transaction_log");
+ PRINT("");
+ PRINT("------ BINDER TRANSACTIONS ------");
+ DUMP("/proc/binder/transactions");
+ PRINT("");
+ PRINT("------ BINDER STATS ------");
+ DUMP("/proc/binder/stats");
+ PRINT("");
+ PRINT("------ BINDER PROCESS STATE: $i ------");
+ DUMP_FILES("/proc/binder/proc");
+ PRINT("------ FILESYSTEMS ------");
+ EXEC("df");
+ PRINT("------ PACKAGE SETTINGS ------");
+ DUMP("/data/system/packages.xml");
+ PRINT("------ PACKAGE UID ERRORS ------");
+ DUMP("/data/system/uiderrors.txt");
+ PRINT("------ LAST KERNEL LOG ------");
+ DUMP("/proc/last_kmsg");
+ }
+ PRINT("========================================================");
+ PRINT("== build.prop");
+ PRINT("========================================================");
+
+ /* the crash server parses key-value pairs between the VERSION INFO and
+ * END lines so we can aggregate crash reports based on this data.
+ */
+ PRINT("------ VERSION INFO ------");
+ print_date("currenttime=", &now);
+ DUMP_PROMPT("kernel.version=", "/proc/version");
+ DUMP_PROMPT("kernel.cmdline=", "/proc/cmdline");
+ DUMP("/system/build.prop");
+ PROPERTY("gsm.version.ril-impl");
+ PROPERTY("gsm.version.baseband");
+ PROPERTY("gsm.imei");
+ PROPERTY("gsm.sim.operator.numeric");
+ PROPERTY("gsm.operator.alpha");
+ PRINT("------ END ------");
+
+ if (full) {
+ PRINT("========================================================");
+ PRINT("== dumpsys");
+ PRINT("========================================================");
+ EXEC("dumpsys");
+ }
+}
+
+/* used to check the file name passed via argv[0] */
+static int check_command_name(const char* name, const char* test) {
+ int name_length, test_length;
+
+ if (!strcmp(name, test))
+ return 1;
+
+ name_length = strlen(name);
+ test_length = strlen(test);
+
+ if (name_length > test_length + 2) {
+ name += (name_length - test_length);
+ if (name[-1] != '/')
+ return 0;
+ if (!strcmp(name, test))
+ return 1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ int dumpcrash = check_command_name(argv[0], "dumpcrash");
+ int bugreport = check_command_name(argv[0], "bugreport");
+ int add_date = 0;
+ char* outfile = 0;
+ int vibrate = 0;
+ int compress = 0;
+ int c, fd, vibrate_fd, fds[2];
+ char path[PATH_MAX];
+ pid_t pid;
+
+ /* set as high priority, and protect from OOM killer */
+ setpriority(PRIO_PROCESS, 0, -20);
+ protect_from_oom_killer();
+
+ get_time(&now);
+
+ if (bugreport) {
+ do {
+ c = getopt(argc, argv, "do:vz");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'd':
+ add_date = 1;
+ break;
+ case 'o':
+ outfile = optarg;
+ break;
+ case 'v':
+ vibrate = 1;
+ break;
+ case 'z':
+ compress = 1;
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ exit(1);
+ }
+ } while (1);
+ }
+
+ /* open vibrator before switching user */
+ if (vibrate) {
+ vibrate_fd = open("/sys/class/timed_output/vibrator/enable", O_WRONLY);
+ if (vibrate_fd > 0)
+ fcntl(vibrate_fd, F_SETFD, FD_CLOEXEC);
+ } else
+ vibrate_fd = -1;
+
+ /* switch to non-root user and group */
+ setgid(AID_LOG);
+ setuid(AID_SHELL);
+
+ /* make it safe to use both printf and STDOUT_FILENO */
+ setvbuf(stdout, 0, _IONBF, 0);
+
+ if (outfile) {
+ if (strlen(outfile) > sizeof(path) - 100)
+ exit(1);
+
+ strcpy(path, outfile);
+ if (add_date) {
+ char date[260];
+ strftime(date, sizeof(date),
+ "-%Y-%m-%d-%H-%M-%S",
+ &now);
+ strcat(path, date);
+ }
+ if (compress)
+ strcat(path, ".gz");
+ else
+ strcat(path, ".txt");
+
+ /* ensure that all directories in the path exist */
+ create_directories(path);
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0)
+ return fd;
+
+ if (compress) {
+ pipe(fds);
+
+ /* redirect our stdout to the pipe */
+ dup2(fds[1], STDOUT_FILENO);
+ close(fds[1]);
+
+ if ((pid = fork()) < 0)
+ {
+ fprintf(stderr, "fork error\n");
+ exit(1);
+ }
+
+ if (pid) {
+ /* parent case */
+
+ /* close our copy of the input to gzip */
+ close(fds[0]);
+ /* close our copy of the output file */
+ close(fd);
+ } else {
+ /* child case */
+
+ /* redirect our input pipe to stdin */
+ dup2(fds[0], STDIN_FILENO);
+ close(fds[0]);
+
+ /* redirect stdout to the output file */
+ dup2(fd, STDOUT_FILENO);
+ close(fd);
+
+ /* run gzip to postprocess our output */
+ execv("/system/bin/gzip", gzip_args);
+ fprintf(stderr, "execv returned\n");
+ }
+ } else {
+ /* redirect stdout to the output file */
+ dup2(fd, STDOUT_FILENO);
+ close(fd);
+ }
+ }
+ /* else everything will print to stdout */
+
+ if (vibrate) {
+ vibrate_pattern(vibrate_fd, start_pattern);
+ }
+ dumpstate(!dumpcrash);
+ if (vibrate) {
+ vibrate_pattern(vibrate_fd, end_pattern);
+ close(vibrate_fd);
+ }
+
+ /* so gzip will terminate */
+ close(STDOUT_FILENO);
+
+ return 0;
+}
+