blob: 957a44912c7782462e260089716a98264bef24d6 [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>
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -070013#include <android-base/stringprintf.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080014#include <android-base/unique_fd.h>
15#include <binder/IServiceManager.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070016#include <binder/Parcel.h>
17#include <binder/ProcessState.h>
Mathias Agopian002e1e52013-05-06 20:20:50 -070018#include <binder/TextOutput.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080019#include <utils/Log.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070020#include <utils/Vector.h>
21
Josh Gao4b8f6f92016-02-29 16:20:34 -080022#include <fcntl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070023#include <getopt.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070024#include <stdio.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080025#include <stdlib.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070026#include <string.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080027#include <sys/poll.h>
28#include <sys/socket.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070029#include <sys/time.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080030#include <sys/types.h>
31#include <unistd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070032
33using namespace android;
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -070034using android::base::StringPrintf;
Josh Gao4b8f6f92016-02-29 16:20:34 -080035using android::base::unique_fd;
36using android::base::WriteFully;
Colin Crossf45fa6b2012-03-26 12:38:26 -070037
38static int sort_func(const String16* lhs, const String16* rhs)
39{
40 return lhs->compare(*rhs);
41}
42
Felipe Lemebbfd2b82016-02-03 11:16:27 -080043static void usage() {
44 fprintf(stderr,
45 "usage: dumpsys\n"
46 " To dump all services.\n"
47 "or:\n"
Thierry Strudel8b78b752016-03-22 10:25:44 -070048 " dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
Felipe Lemebbfd2b82016-02-03 11:16:27 -080049 " --help: shows this help\n"
50 " -l: only list services, do not dump them\n"
Thierry Strudel8b78b752016-03-22 10:25:44 -070051 " -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
Felipe Leme859aef62016-02-03 12:17:10 -080052 " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
53 " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
54}
55
56bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
57 for (const auto& candidate : skipped) {
58 if (candidate == service) {
59 return true;
60 }
61 }
62 return false;
Felipe Lemebbfd2b82016-02-03 11:16:27 -080063}
64
Colin Crossf45fa6b2012-03-26 12:38:26 -070065int main(int argc, char* const argv[])
66{
JP Abgrall3e03d3f2012-05-11 14:14:09 -070067 signal(SIGPIPE, SIG_IGN);
Colin Crossf45fa6b2012-03-26 12:38:26 -070068 sp<IServiceManager> sm = defaultServiceManager();
69 fflush(stdout);
70 if (sm == NULL) {
Felipe Lemebbfd2b82016-02-03 11:16:27 -080071 ALOGE("Unable to get default service manager!");
Colin Crossf45fa6b2012-03-26 12:38:26 -070072 aerr << "dumpsys: Unable to get default service manager!" << endl;
73 return 20;
74 }
75
76 Vector<String16> services;
77 Vector<String16> args;
Felipe Leme859aef62016-02-03 12:17:10 -080078 Vector<String16> skippedServices;
keunyoungcaad5552013-06-13 15:08:51 -070079 bool showListOnly = false;
Thierry Strudel8b78b752016-03-22 10:25:44 -070080 bool skipServices = false;
81 int timeoutArg = 10;
82 static struct option longOptions[] = {
83 {"skip", no_argument, 0, 0 },
84 {"help", no_argument, 0, 0 },
85 { 0, 0, 0, 0 }
86 };
87
88 while (1) {
89 int c;
90 int optionIndex = 0;
91
92 c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex);
93
94 if (c == -1) {
95 break;
Felipe Lemebbfd2b82016-02-03 11:16:27 -080096 }
Thierry Strudel8b78b752016-03-22 10:25:44 -070097
98 switch (c) {
99 case 0:
100 if (!strcmp(longOptions[optionIndex].name, "skip")) {
101 skipServices = true;
102 } else if (!strcmp(longOptions[optionIndex].name, "help")) {
103 usage();
104 return 0;
105 }
106 break;
107
108 case 't':
109 {
110 char *endptr;
111 timeoutArg = strtol(optarg, &endptr, 10);
112 if (*endptr != '\0' || timeoutArg <= 0) {
113 fprintf(stderr, "Error: invalid timeout number: '%s'\n", optarg);
114 return -1;
115 }
116 }
117 break;
118
119 case 'l':
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800120 showListOnly = true;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700121 break;
122
123 default:
124 fprintf(stderr, "\n");
125 usage();
126 return -1;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800127 }
keunyoungcaad5552013-06-13 15:08:51 -0700128 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700129
130 for (int i = optind; i < argc; i++) {
131 if (skipServices) {
132 skippedServices.add(String16(argv[i]));
133 } else {
134 if (i == optind) {
135 services.add(String16(argv[i]));
136 } else {
137 args.add(String16(argv[i]));
Felipe Leme859aef62016-02-03 12:17:10 -0800138 }
139 }
140 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700141
142 if ((skipServices && skippedServices.empty()) ||
Thierry Strudel8b78b752016-03-22 10:25:44 -0700143 (showListOnly && (!services.empty() || !skippedServices.empty()))) {
144 usage();
145 return -1;
146 }
147
Thierry Strudel159a8322016-03-23 11:22:34 -0700148 if (services.empty() || showListOnly) {
Felipe Leme859aef62016-02-03 12:17:10 -0800149 // gets all services
Colin Crossf45fa6b2012-03-26 12:38:26 -0700150 services = sm->listServices();
151 services.sort(sort_func);
152 args.add(String16("-a"));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700153 }
154
155 const size_t N = services.size();
156
157 if (N > 1) {
158 // first print a list of the current services
159 aout << "Currently running services:" << endl;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800160
Colin Crossf45fa6b2012-03-26 12:38:26 -0700161 for (size_t i=0; i<N; i++) {
162 sp<IBinder> service = sm->checkService(services[i]);
163 if (service != NULL) {
Felipe Leme859aef62016-02-03 12:17:10 -0800164 bool skipped = IsSkipped(skippedServices, services[i]);
165 aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700166 }
167 }
168 }
169
keunyoungcaad5552013-06-13 15:08:51 -0700170 if (showListOnly) {
171 return 0;
172 }
173
Josh Gao4b8f6f92016-02-29 16:20:34 -0800174 for (size_t i = 0; i < N; i++) {
175 String16 service_name = std::move(services[i]);
176 if (IsSkipped(skippedServices, service_name)) continue;
Felipe Leme859aef62016-02-03 12:17:10 -0800177
Josh Gao4b8f6f92016-02-29 16:20:34 -0800178 sp<IBinder> service = sm->checkService(service_name);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700179 if (service != NULL) {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800180 int sfd[2];
181
Josh Gao49f0a0c2016-03-04 13:12:29 -0800182 if (pipe(sfd) != 0) {
183 aerr << "Failed to create pipe to dump service info for " << service_name
Josh Gao4b8f6f92016-02-29 16:20:34 -0800184 << ": " << strerror(errno) << endl;
185 continue;
186 }
187
188 unique_fd local_end(sfd[0]);
189 unique_fd remote_end(sfd[1]);
190 sfd[0] = sfd[1] = -1;
191
Colin Crossf45fa6b2012-03-26 12:38:26 -0700192 if (N > 1) {
193 aout << "------------------------------------------------------------"
194 "-------------------" << endl;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800195 aout << "DUMP OF SERVICE " << service_name << ":" << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700196 }
Josh Gao4b8f6f92016-02-29 16:20:34 -0800197
198 // dump blocks until completion, so spawn a thread..
199 std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {
200 int err = service->dump(remote_end.get(), args);
201
202 // It'd be nice to be able to close the remote end of the socketpair before the dump
203 // call returns, to terminate our reads if the other end closes their copy of the
204 // file descriptor, but then hangs for some reason. There doesn't seem to be a good
205 // way to do this, though.
206 remote_end.clear();
207
208 if (err != 0) {
209 aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
210 << endl;
211 }
212 });
213
Thierry Strudel8b78b752016-03-22 10:25:44 -0700214 auto timeout = std::chrono::seconds(timeoutArg);
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700215 auto start = std::chrono::steady_clock::now();
216 auto end = start + timeout;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800217
218 struct pollfd pfd = {
219 .fd = local_end.get(),
220 .events = POLLIN
221 };
222
223 bool timed_out = false;
224 bool error = false;
225 while (true) {
226 // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
227 auto time_left_ms = [end]() {
228 auto now = std::chrono::steady_clock::now();
229 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
230 return std::max(diff.count(), 0ll);
231 };
232
233 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
234 if (rc < 0) {
235 aerr << "Error in poll while dumping service " << service_name << " : "
236 << strerror(errno) << endl;
237 error = true;
238 break;
239 } else if (rc == 0) {
240 timed_out = true;
241 break;
242 }
243
244 char buf[4096];
245 rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf)));
246 if (rc < 0) {
247 aerr << "Failed to read while dumping service " << service_name << ": "
248 << strerror(errno) << endl;
249 error = true;
250 break;
251 } else if (rc == 0) {
252 // EOF.
253 break;
254 }
255
256 if (!WriteFully(STDOUT_FILENO, buf, rc)) {
257 aerr << "Failed to write while dumping service " << service_name << ": "
258 << strerror(errno) << endl;
259 error = true;
260 break;
261 }
262 }
263
264 if (timed_out) {
265 aout << endl << "*** SERVICE DUMP TIMEOUT EXPIRED ***" << endl << endl;
266 }
267
268 if (timed_out || error) {
269 dump_thread.detach();
270 } else {
271 dump_thread.join();
Colin Crossf45fa6b2012-03-26 12:38:26 -0700272 }
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700273
274 if (N > 1) {
275 std::chrono::duration<double> elapsed_seconds =
276 std::chrono::steady_clock::now() - start;
277 aout << StringPrintf("------ %.3fs was the duration of '", elapsed_seconds.count()).
278 c_str();
279 aout << service_name << "' ------" << endl;
280 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700281 } else {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800282 aerr << "Can't find service: " << service_name << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700283 }
284 }
285
286 return 0;
287}