blob: 7e5bbc578b6eea5caa57b1bef975c7bf4e7c8824 [file] [log] [blame]
Colin Crossf45fa6b2012-03-26 12:38:26 -07001/*
2 * Command that dumps interesting system state to the log.
3 *
4 */
5
6#define LOG_TAG "dumpsys"
7
Josh Gao4b8f6f92016-02-29 16:20:34 -08008#include <algorithm>
9#include <chrono>
10#include <thread>
11
12#include <android-base/file.h>
13#include <android-base/unique_fd.h>
14#include <binder/IServiceManager.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070015#include <binder/Parcel.h>
16#include <binder/ProcessState.h>
Mathias Agopian002e1e52013-05-06 20:20:50 -070017#include <binder/TextOutput.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080018#include <utils/Log.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070019#include <utils/Vector.h>
20
Josh Gao4b8f6f92016-02-29 16:20:34 -080021#include <fcntl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070022#include <getopt.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070023#include <stdio.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080024#include <stdlib.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070025#include <string.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080026#include <sys/poll.h>
27#include <sys/socket.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070028#include <sys/time.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080029#include <sys/types.h>
30#include <unistd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070031
32using namespace android;
Josh Gao4b8f6f92016-02-29 16:20:34 -080033using android::base::unique_fd;
34using android::base::WriteFully;
Colin Crossf45fa6b2012-03-26 12:38:26 -070035
36static int sort_func(const String16* lhs, const String16* rhs)
37{
38 return lhs->compare(*rhs);
39}
40
Felipe Lemebbfd2b82016-02-03 11:16:27 -080041static void usage() {
42 fprintf(stderr,
43 "usage: dumpsys\n"
44 " To dump all services.\n"
45 "or:\n"
Thierry Strudel8b78b752016-03-22 10:25:44 -070046 " dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
Felipe Lemebbfd2b82016-02-03 11:16:27 -080047 " --help: shows this help\n"
48 " -l: only list services, do not dump them\n"
Thierry Strudel8b78b752016-03-22 10:25:44 -070049 " -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
Felipe Leme859aef62016-02-03 12:17:10 -080050 " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
51 " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
52}
53
54bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
55 for (const auto& candidate : skipped) {
56 if (candidate == service) {
57 return true;
58 }
59 }
60 return false;
Felipe Lemebbfd2b82016-02-03 11:16:27 -080061}
62
Colin Crossf45fa6b2012-03-26 12:38:26 -070063int main(int argc, char* const argv[])
64{
JP Abgrall3e03d3f2012-05-11 14:14:09 -070065 signal(SIGPIPE, SIG_IGN);
Colin Crossf45fa6b2012-03-26 12:38:26 -070066 sp<IServiceManager> sm = defaultServiceManager();
67 fflush(stdout);
68 if (sm == NULL) {
Felipe Lemebbfd2b82016-02-03 11:16:27 -080069 ALOGE("Unable to get default service manager!");
Colin Crossf45fa6b2012-03-26 12:38:26 -070070 aerr << "dumpsys: Unable to get default service manager!" << endl;
71 return 20;
72 }
73
74 Vector<String16> services;
75 Vector<String16> args;
Felipe Leme859aef62016-02-03 12:17:10 -080076 Vector<String16> skippedServices;
keunyoungcaad5552013-06-13 15:08:51 -070077 bool showListOnly = false;
Thierry Strudel8b78b752016-03-22 10:25:44 -070078 bool skipServices = false;
79 int timeoutArg = 10;
80 static struct option longOptions[] = {
81 {"skip", no_argument, 0, 0 },
82 {"help", no_argument, 0, 0 },
83 { 0, 0, 0, 0 }
84 };
85
86 while (1) {
87 int c;
88 int optionIndex = 0;
89
90 c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex);
91
92 if (c == -1) {
93 break;
Felipe Lemebbfd2b82016-02-03 11:16:27 -080094 }
Thierry Strudel8b78b752016-03-22 10:25:44 -070095
96 switch (c) {
97 case 0:
98 if (!strcmp(longOptions[optionIndex].name, "skip")) {
99 skipServices = true;
100 } else if (!strcmp(longOptions[optionIndex].name, "help")) {
101 usage();
102 return 0;
103 }
104 break;
105
106 case 't':
107 {
108 char *endptr;
109 timeoutArg = strtol(optarg, &endptr, 10);
110 if (*endptr != '\0' || timeoutArg <= 0) {
111 fprintf(stderr, "Error: invalid timeout number: '%s'\n", optarg);
112 return -1;
113 }
114 }
115 break;
116
117 case 'l':
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800118 showListOnly = true;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700119 break;
120
121 default:
122 fprintf(stderr, "\n");
123 usage();
124 return -1;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800125 }
keunyoungcaad5552013-06-13 15:08:51 -0700126 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700127
128 for (int i = optind; i < argc; i++) {
129 if (skipServices) {
130 skippedServices.add(String16(argv[i]));
131 } else {
132 if (i == optind) {
133 services.add(String16(argv[i]));
134 } else {
135 args.add(String16(argv[i]));
Felipe Leme859aef62016-02-03 12:17:10 -0800136 }
137 }
138 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700139
140 if ((skipServices && skippedServices.empty()) ||
Thierry Strudel8b78b752016-03-22 10:25:44 -0700141 (showListOnly && (!services.empty() || !skippedServices.empty()))) {
142 usage();
143 return -1;
144 }
145
Thierry Strudel159a8322016-03-23 11:22:34 -0700146 if (services.empty() || showListOnly) {
Felipe Leme859aef62016-02-03 12:17:10 -0800147 // gets all services
Colin Crossf45fa6b2012-03-26 12:38:26 -0700148 services = sm->listServices();
149 services.sort(sort_func);
150 args.add(String16("-a"));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700151 }
152
153 const size_t N = services.size();
154
155 if (N > 1) {
156 // first print a list of the current services
157 aout << "Currently running services:" << endl;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800158
Colin Crossf45fa6b2012-03-26 12:38:26 -0700159 for (size_t i=0; i<N; i++) {
160 sp<IBinder> service = sm->checkService(services[i]);
161 if (service != NULL) {
Felipe Leme859aef62016-02-03 12:17:10 -0800162 bool skipped = IsSkipped(skippedServices, services[i]);
163 aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700164 }
165 }
166 }
167
keunyoungcaad5552013-06-13 15:08:51 -0700168 if (showListOnly) {
169 return 0;
170 }
171
Josh Gao4b8f6f92016-02-29 16:20:34 -0800172 for (size_t i = 0; i < N; i++) {
173 String16 service_name = std::move(services[i]);
174 if (IsSkipped(skippedServices, service_name)) continue;
Felipe Leme859aef62016-02-03 12:17:10 -0800175
Josh Gao4b8f6f92016-02-29 16:20:34 -0800176 sp<IBinder> service = sm->checkService(service_name);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700177 if (service != NULL) {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800178 int sfd[2];
179
Josh Gao49f0a0c2016-03-04 13:12:29 -0800180 if (pipe(sfd) != 0) {
181 aerr << "Failed to create pipe to dump service info for " << service_name
Josh Gao4b8f6f92016-02-29 16:20:34 -0800182 << ": " << strerror(errno) << endl;
183 continue;
184 }
185
186 unique_fd local_end(sfd[0]);
187 unique_fd remote_end(sfd[1]);
188 sfd[0] = sfd[1] = -1;
189
Colin Crossf45fa6b2012-03-26 12:38:26 -0700190 if (N > 1) {
191 aout << "------------------------------------------------------------"
192 "-------------------" << endl;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800193 aout << "DUMP OF SERVICE " << service_name << ":" << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700194 }
Josh Gao4b8f6f92016-02-29 16:20:34 -0800195
196 // dump blocks until completion, so spawn a thread..
197 std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {
198 int err = service->dump(remote_end.get(), args);
199
200 // It'd be nice to be able to close the remote end of the socketpair before the dump
201 // call returns, to terminate our reads if the other end closes their copy of the
202 // file descriptor, but then hangs for some reason. There doesn't seem to be a good
203 // way to do this, though.
204 remote_end.clear();
205
206 if (err != 0) {
207 aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
208 << endl;
209 }
210 });
211
Thierry Strudel8b78b752016-03-22 10:25:44 -0700212 auto timeout = std::chrono::seconds(timeoutArg);
Josh Gao4b8f6f92016-02-29 16:20:34 -0800213 auto end = std::chrono::steady_clock::now() + timeout;
214
215 struct pollfd pfd = {
216 .fd = local_end.get(),
217 .events = POLLIN
218 };
219
220 bool timed_out = false;
221 bool error = false;
222 while (true) {
223 // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
224 auto time_left_ms = [end]() {
225 auto now = std::chrono::steady_clock::now();
226 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
227 return std::max(diff.count(), 0ll);
228 };
229
230 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
231 if (rc < 0) {
232 aerr << "Error in poll while dumping service " << service_name << " : "
233 << strerror(errno) << endl;
234 error = true;
235 break;
236 } else if (rc == 0) {
237 timed_out = true;
238 break;
239 }
240
241 char buf[4096];
242 rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf)));
243 if (rc < 0) {
244 aerr << "Failed to read while dumping service " << service_name << ": "
245 << strerror(errno) << endl;
246 error = true;
247 break;
248 } else if (rc == 0) {
249 // EOF.
250 break;
251 }
252
253 if (!WriteFully(STDOUT_FILENO, buf, rc)) {
254 aerr << "Failed to write while dumping service " << service_name << ": "
255 << strerror(errno) << endl;
256 error = true;
257 break;
258 }
259 }
260
261 if (timed_out) {
262 aout << endl << "*** SERVICE DUMP TIMEOUT EXPIRED ***" << endl << endl;
263 }
264
265 if (timed_out || error) {
266 dump_thread.detach();
267 } else {
268 dump_thread.join();
Colin Crossf45fa6b2012-03-26 12:38:26 -0700269 }
270 } else {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800271 aerr << "Can't find service: " << service_name << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700272 }
273 }
274
275 return 0;
276}