• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/resource.h>
24 #include <sys/stat.h>
25 #include <sys/time.h>
26 #include <sys/wait.h>
27 #include <unistd.h>
28 
29 #include <cutils/properties.h>
30 
31 #include "private/android_filesystem_config.h"
32 
33 #define LOG_TAG "dumpstate"
34 #include <utils/Log.h>
35 
36 #include "dumpstate.h"
37 
38 /* read before root is shed */
39 static char cmdline_buf[16384] = "(unknown)";
40 static const char *dump_traces_path = NULL;
41 
42 /* dumps the current system state to stdout */
dumpstate()43 static void dumpstate() {
44     time_t now = time(NULL);
45     char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
46     char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
47     char network[PROPERTY_VALUE_MAX], date[80];
48 
49     property_get("ro.build.display.id", build, "(unknown)");
50     property_get("ro.build.fingerprint", fingerprint, "(unknown)");
51     property_get("ro.baseband", radio, "(unknown)");
52     property_get("ro.bootloader", bootloader, "(unknown)");
53     property_get("gsm.operator.alpha", network, "(unknown)");
54     strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
55 
56     printf("========================================================\n");
57     printf("== dumpstate: %s\n", date);
58     printf("========================================================\n");
59 
60     printf("\n");
61     printf("Build: %s\n", build);
62     printf("Bootloader: %s\n", bootloader);
63     printf("Radio: %s\n", radio);
64     printf("Network: %s\n", network);
65 
66     printf("Kernel: ");
67     dump_file(NULL, "/proc/version");
68     printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
69     printf("\n");
70 
71     dump_file("MEMORY INFO", "/proc/meminfo");
72     run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL);
73     run_command("PROCRANK", 20, "procrank", NULL);
74     dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
75     dump_file("VMALLOC INFO", "/proc/vmallocinfo");
76     dump_file("SLAB INFO", "/proc/slabinfo");
77     dump_file("ZONEINFO", "/proc/zoneinfo");
78 
79     run_command("SYSTEM LOG", 20, "logcat", "-v", "time", "-d", "*:v", NULL);
80 
81     /* show the traces we collected in main(), if that was done */
82     if (dump_traces_path != NULL) {
83         dump_file("VM TRACES JUST NOW", dump_traces_path);
84     }
85 
86     /* only show ANR traces if they're less than 15 minutes old */
87     struct stat st;
88     char anr_traces_path[PATH_MAX];
89     property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
90     if (!anr_traces_path[0]) {
91         printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
92     } else if (stat(anr_traces_path, &st)) {
93         printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
94     } else {
95         dump_file("VM TRACES AT LAST ANR", anr_traces_path);
96     }
97 
98     // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
99     run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "time", "-d", "*:v", NULL);
100     run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "time", "-d", "*:v", NULL);
101 
102     run_command("NETWORK INTERFACES", 10, "netcfg", NULL);
103     dump_file("NETWORK ROUTES", "/proc/net/route");
104     dump_file("ARP CACHE", "/proc/net/arp");
105 
106 #ifdef FWDUMP_bcm4329
107     run_command("DUMP WIFI FIRMWARE LOG", 60,
108             "su", "root", "dhdutil", "-i", "eth0", "upload", "/data/local/tmp/wlan_crash.dump", NULL);
109 #endif
110 
111     print_properties();
112 
113     run_command("KERNEL LOG", 20, "dmesg", NULL);
114 
115     dump_file("KERNEL WAKELOCKS", "/proc/wakelocks");
116     dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
117 
118     run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
119     run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
120 
121     run_command("PROCESSES", 10, "ps", "-P", NULL);
122     run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL);
123     run_command("LIBRANK", 10, "librank", NULL);
124 
125     dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
126     dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
127     dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
128     dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
129     dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
130 
131     run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);
132 
133     dump_file("PACKAGE SETTINGS", "/data/system/packages.xml");
134     dump_file("PACKAGE UID ERRORS", "/data/system/uiderrors.txt");
135 
136     dump_file("LAST KMSG", "/proc/last_kmsg");
137     run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
138     dump_file("LAST PANIC CONSOLE", "/data/dontpanic/apanic_console");
139     dump_file("LAST PANIC THREADS", "/data/dontpanic/apanic_threads");
140 
141     for_each_pid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
142 
143     printf("------ BACKLIGHTS ------\n");
144     printf("LCD brightness=");
145     dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
146     printf("Button brightness=");
147     dump_file(NULL, "/sys/class/leds/button-backlight/brightness");
148     printf("Keyboard brightness=");
149     dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");
150     printf("ALS mode=");
151     dump_file(NULL, "/sys/class/leds/lcd-backlight/als");
152     printf("LCD driver registers:\n");
153     dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
154     printf("\n");
155 
156     printf("========================================================\n");
157     printf("== Android Framework Services\n");
158     printf("========================================================\n");
159 
160     /* the full dumpsys is starting to take a long time, so we need
161        to increase its timeout.  we really need to do the timeouts in
162        dumpsys itself... */
163     run_command("DUMPSYS", 60, "dumpsys", NULL);
164 }
165 
usage()166 static void usage() {
167     fprintf(stderr, "usage: dumpstate [-d] [-o file] [-s] [-z]\n"
168             "  -d: append date to filename (requires -o)\n"
169             "  -o: write to file (instead of stdout)\n"
170             "  -s: write output to control socket (for init)\n"
171             "  -z: gzip output (requires -o)\n");
172 }
173 
main(int argc,char * argv[])174 int main(int argc, char *argv[]) {
175     int do_add_date = 0;
176     int do_compress = 0;
177     char* use_outfile = 0;
178     int use_socket = 0;
179 
180     LOGI("begin\n");
181 
182     /* set as high priority, and protect from OOM killer */
183     setpriority(PRIO_PROCESS, 0, -20);
184     FILE *oom_adj = fopen("/proc/self/oom_adj", "w");
185     if (oom_adj) {
186         fputs("-17", oom_adj);
187         fclose(oom_adj);
188     }
189 
190     /* very first thing, collect VM traces from Dalvik (needs root) */
191     dump_traces_path = dump_vm_traces();
192 
193     int c;
194     while ((c = getopt(argc, argv, "dho:svz")) != -1) {
195         switch (c) {
196             case 'd': do_add_date = 1;       break;
197             case 'o': use_outfile = optarg;  break;
198             case 's': use_socket = 1;        break;
199             case 'v': break;  // compatibility no-op
200             case 'z': do_compress = 6;       break;
201             case '?': printf("\n");
202             case 'h':
203                 usage();
204                 exit(1);
205         }
206     }
207 
208     /* open the vibrator before dropping root */
209     FILE *vibrator = fopen("/sys/class/timed_output/vibrator/enable", "w");
210     if (vibrator) fcntl(fileno(vibrator), F_SETFD, FD_CLOEXEC);
211 
212     /* read /proc/cmdline before dropping root */
213     FILE *cmdline = fopen("/proc/cmdline", "r");
214     if (cmdline != NULL) {
215         fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
216         fclose(cmdline);
217     }
218 
219     if (getuid() == 0) {
220         /* switch to non-root user and group */
221         gid_t groups[] = { AID_LOG, AID_SDCARD_RW, AID_MOUNT };
222         if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
223             LOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
224             return -1;
225         }
226         if (setgid(AID_SHELL) != 0) {
227             LOGE("Unable to setgid, aborting: %s\n", strerror(errno));
228             return -1;
229         }
230         if (setuid(AID_SHELL) != 0) {
231             LOGE("Unable to setuid, aborting: %s\n", strerror(errno));
232             return -1;
233         }
234     }
235 
236     char path[PATH_MAX], tmp_path[PATH_MAX];
237     pid_t gzip_pid = -1;
238 
239     if (use_socket) {
240         redirect_to_socket(stdout, "dumpstate");
241     } else if (use_outfile) {
242         strlcpy(path, use_outfile, sizeof(path));
243         if (do_add_date) {
244             char date[80];
245             time_t now = time(NULL);
246             strftime(date, sizeof(date), "-%Y-%m-%d-%H-%M-%S", localtime(&now));
247             strlcat(path, date, sizeof(path));
248         }
249         strlcat(path, ".txt", sizeof(path));
250         if (do_compress) strlcat(path, ".gz", sizeof(path));
251         strlcpy(tmp_path, path, sizeof(tmp_path));
252         strlcat(tmp_path, ".tmp", sizeof(tmp_path));
253         gzip_pid = redirect_to_file(stdout, tmp_path, do_compress);
254     }
255 
256     /* bzzzzzz */
257     if (vibrator) {
258         fputs("150", vibrator);
259         fflush(vibrator);
260     }
261 
262     dumpstate();
263 
264     /* bzzz bzzz bzzz */
265     if (vibrator) {
266         int i;
267         for (i = 0; i < 3; i++) {
268             fputs("75\n", vibrator);
269             fflush(vibrator);
270             usleep((75 + 50) * 1000);
271         }
272         fclose(vibrator);
273     }
274 
275     /* wait for gzip to finish, otherwise it might get killed when we exit */
276     if (gzip_pid > 0) {
277         fclose(stdout);
278         waitpid(gzip_pid, NULL, 0);
279     }
280 
281     /* rename the (now complete) .tmp file to its final location */
282     if (use_outfile && rename(tmp_path, path)) {
283         fprintf(stderr, "rename(%s, %s): %s\n", tmp_path, path, strerror(errno));
284     }
285 
286     LOGI("done\n");
287 
288     return 0;
289 }
290