blob: cc951c1bcbd14bb11c07db173187f339a654ae1a [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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 <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
21#include <sys/stat.h>
22#include <limits.h>
23#include <fcntl.h>
24#include <sys/time.h>
25#include <sys/resource.h>
26
27#include "private/android_filesystem_config.h"
28
29#include "dumpstate.h"
30
31static char* const gzip_args[] = { "gzip", "-6", 0 };
32static int start_pattern[] = { 150, 0 };
33static int end_pattern[] = { 75, 50, 75, 50, 75, 0 };
34
35static struct tm now;
36
37/* dumps the current system state to stdout */
38static void dumpstate(int full) {
39 if (full) {
40 PRINT("========================================================");
41 PRINT("== dumpstate");
42 PRINT("========================================================");
43 PRINT("------ MEMORY INFO ------");
44 DUMP("/proc/meminfo");
45 PRINT("------ CPU INFO ------");
46 EXEC7("top", "-n", "1", "-d", "1", "-m", "30", "-t");
47 PRINT("------ PROCRANK ------");
48 EXEC_XBIN("procrank");
49 PRINT("------ VIRTUAL MEMORY STATS ------");
50 DUMP("/proc/vmstat");
51 PRINT("------ SLAB INFO ------");
52 DUMP("/proc/slabinfo");
53 PRINT("------ ZONEINFO ------");
54 DUMP("/proc/zoneinfo");
55 PRINT("------ SYSTEM LOG ------");
56 EXEC4("logcat", "-v", "time", "-d", "*:v");
57 PRINT("------ VM TRACES ------");
58 DUMP("/data/anr/traces.txt");
59 PRINT("------ EVENT LOG TAGS ------");
60 DUMP("/etc/event-log-tags");
61 PRINT("------ EVENT LOG ------");
62 EXEC6("logcat", "-b", "events", "-v", "time", "-d", "*:v");
63 PRINT("------ RADIO LOG ------");
64 EXEC6("logcat", "-b", "radio", "-v", "time", "-d", "*:v");
65 PRINT("------ NETWORK STATE ------");
66 PRINT("Interfaces:");
67 EXEC("netcfg");
68 PRINT("");
69 PRINT("Routes:");
70 DUMP("/proc/net/route");
71 PRINT("------ SYSTEM PROPERTIES ------");
72 print_properties();
73 PRINT("------ KERNEL LOG ------");
74 EXEC("dmesg");
75 PRINT("------ KERNEL WAKELOCKS ------");
76 DUMP("/proc/wakelocks");
77 PRINT("");
78 PRINT("------ PROCESSES ------");
79 EXEC("ps");
80 PRINT("------ PROCESSES AND THREADS ------");
81 EXEC2("ps", "-t", "-p");
82 PRINT("------ LIBRANK ------");
83 EXEC_XBIN("librank");
84 PRINT("------ BINDER FAILED TRANSACTION LOG ------");
85 DUMP("/proc/binder/failed_transaction_log");
86 PRINT("");
87 PRINT("------ BINDER TRANSACTION LOG ------");
88 DUMP("/proc/binder/transaction_log");
89 PRINT("");
90 PRINT("------ BINDER TRANSACTIONS ------");
91 DUMP("/proc/binder/transactions");
92 PRINT("");
93 PRINT("------ BINDER STATS ------");
94 DUMP("/proc/binder/stats");
95 PRINT("");
96 PRINT("------ BINDER PROCESS STATE: $i ------");
97 DUMP_FILES("/proc/binder/proc");
98 PRINT("------ FILESYSTEMS ------");
99 EXEC("df");
100 PRINT("------ PACKAGE SETTINGS ------");
101 DUMP("/data/system/packages.xml");
102 PRINT("------ PACKAGE UID ERRORS ------");
103 DUMP("/data/system/uiderrors.txt");
104 PRINT("------ LAST KERNEL LOG ------");
105 DUMP("/proc/last_kmsg");
106 }
107 PRINT("========================================================");
108 PRINT("== build.prop");
109 PRINT("========================================================");
110
111 /* the crash server parses key-value pairs between the VERSION INFO and
112 * END lines so we can aggregate crash reports based on this data.
113 */
114 PRINT("------ VERSION INFO ------");
115 print_date("currenttime=", &now);
116 DUMP_PROMPT("kernel.version=", "/proc/version");
117 DUMP_PROMPT("kernel.cmdline=", "/proc/cmdline");
118 DUMP("/system/build.prop");
119 PROPERTY("gsm.version.ril-impl");
120 PROPERTY("gsm.version.baseband");
121 PROPERTY("gsm.imei");
122 PROPERTY("gsm.sim.operator.numeric");
123 PROPERTY("gsm.operator.alpha");
124 PRINT("------ END ------");
125
126 if (full) {
127 PRINT("========================================================");
128 PRINT("== dumpsys");
129 PRINT("========================================================");
The Android Open Source Project4df24232009-03-05 14:34:35 -0800130 /* the full dumpsys is starting to take a long time, so we need
131 to increase its timeout. we really need to do the timeouts in
132 dumpsys itself... */
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700133 EXEC_TIMEOUT("dumpsys", 60);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 }
135}
136
137/* used to check the file name passed via argv[0] */
138static int check_command_name(const char* name, const char* test) {
139 int name_length, test_length;
140
141 if (!strcmp(name, test))
142 return 1;
143
144 name_length = strlen(name);
145 test_length = strlen(test);
146
147 if (name_length > test_length + 2) {
148 name += (name_length - test_length);
149 if (name[-1] != '/')
150 return 0;
151 if (!strcmp(name, test))
152 return 1;
153 }
154
155 return 0;
156}
157
158int main(int argc, char *argv[]) {
159 int dumpcrash = check_command_name(argv[0], "dumpcrash");
160 int bugreport = check_command_name(argv[0], "bugreport");
161 int add_date = 0;
162 char* outfile = 0;
163 int vibrate = 0;
164 int compress = 0;
165 int c, fd, vibrate_fd, fds[2];
166 char path[PATH_MAX];
167 pid_t pid;
Mike Lockwood472be482009-05-22 13:31:42 -0400168 gid_t groups[] = { AID_LOG, AID_SDCARD_RW };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169
170 /* set as high priority, and protect from OOM killer */
171 setpriority(PRIO_PROCESS, 0, -20);
172 protect_from_oom_killer();
173
174 get_time(&now);
175
176 if (bugreport) {
177 do {
178 c = getopt(argc, argv, "do:vz");
179 if (c == EOF)
180 break;
181 switch (c) {
182 case 'd':
183 add_date = 1;
184 break;
185 case 'o':
186 outfile = optarg;
187 break;
188 case 'v':
189 vibrate = 1;
190 break;
191 case 'z':
192 compress = 1;
193 break;
194 case '?':
195 fprintf(stderr, "%s: invalid option -%c\n",
196 argv[0], optopt);
197 exit(1);
198 }
199 } while (1);
200 }
201
202 /* open vibrator before switching user */
203 if (vibrate) {
204 vibrate_fd = open("/sys/class/timed_output/vibrator/enable", O_WRONLY);
205 if (vibrate_fd > 0)
206 fcntl(vibrate_fd, F_SETFD, FD_CLOEXEC);
207 } else
208 vibrate_fd = -1;
209
210 /* switch to non-root user and group */
Mike Lockwood472be482009-05-22 13:31:42 -0400211 setgroups(sizeof(groups)/sizeof(groups[0]), groups);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 setuid(AID_SHELL);
213
214 /* make it safe to use both printf and STDOUT_FILENO */
215 setvbuf(stdout, 0, _IONBF, 0);
216
217 if (outfile) {
218 if (strlen(outfile) > sizeof(path) - 100)
219 exit(1);
220
221 strcpy(path, outfile);
222 if (add_date) {
223 char date[260];
224 strftime(date, sizeof(date),
225 "-%Y-%m-%d-%H-%M-%S",
226 &now);
227 strcat(path, date);
228 }
229 if (compress)
230 strcat(path, ".gz");
231 else
232 strcat(path, ".txt");
233
234 /* ensure that all directories in the path exist */
235 create_directories(path);
236 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
237 if (fd < 0)
238 return fd;
239
240 if (compress) {
241 pipe(fds);
242
243 /* redirect our stdout to the pipe */
244 dup2(fds[1], STDOUT_FILENO);
245 close(fds[1]);
246
247 if ((pid = fork()) < 0)
248 {
249 fprintf(stderr, "fork error\n");
250 exit(1);
251 }
252
253 if (pid) {
254 /* parent case */
255
256 /* close our copy of the input to gzip */
257 close(fds[0]);
258 /* close our copy of the output file */
259 close(fd);
260 } else {
261 /* child case */
262
263 /* redirect our input pipe to stdin */
264 dup2(fds[0], STDIN_FILENO);
265 close(fds[0]);
266
267 /* redirect stdout to the output file */
268 dup2(fd, STDOUT_FILENO);
269 close(fd);
270
271 /* run gzip to postprocess our output */
272 execv("/system/bin/gzip", gzip_args);
273 fprintf(stderr, "execv returned\n");
274 }
275 } else {
276 /* redirect stdout to the output file */
277 dup2(fd, STDOUT_FILENO);
278 close(fd);
279 }
280 }
281 /* else everything will print to stdout */
282
283 if (vibrate) {
284 vibrate_pattern(vibrate_fd, start_pattern);
285 }
286 dumpstate(!dumpcrash);
287 if (vibrate) {
288 vibrate_pattern(vibrate_fd, end_pattern);
289 close(vibrate_fd);
290 }
291
292 /* so gzip will terminate */
293 close(STDOUT_FILENO);
294
295 return 0;
296}
297