blob: 003fcc394da7039e594cec2fd3e8ad87822cc0f7 [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"
Felipe Leme859aef62016-02-03 12:17:10 -080046 " dumpsys [--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"
Felipe Leme859aef62016-02-03 12:17:10 -080049 " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
50 " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
51}
52
53bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
54 for (const auto& candidate : skipped) {
55 if (candidate == service) {
56 return true;
57 }
58 }
59 return false;
Felipe Lemebbfd2b82016-02-03 11:16:27 -080060}
61
Colin Crossf45fa6b2012-03-26 12:38:26 -070062int main(int argc, char* const argv[])
63{
JP Abgrall3e03d3f2012-05-11 14:14:09 -070064 signal(SIGPIPE, SIG_IGN);
Colin Crossf45fa6b2012-03-26 12:38:26 -070065 sp<IServiceManager> sm = defaultServiceManager();
66 fflush(stdout);
67 if (sm == NULL) {
Felipe Lemebbfd2b82016-02-03 11:16:27 -080068 ALOGE("Unable to get default service manager!");
Colin Crossf45fa6b2012-03-26 12:38:26 -070069 aerr << "dumpsys: Unable to get default service manager!" << endl;
70 return 20;
71 }
72
73 Vector<String16> services;
74 Vector<String16> args;
Felipe Leme859aef62016-02-03 12:17:10 -080075 Vector<String16> skippedServices;
keunyoungcaad5552013-06-13 15:08:51 -070076 bool showListOnly = false;
Felipe Lemebbfd2b82016-02-03 11:16:27 -080077 if (argc == 2) {
Felipe Leme859aef62016-02-03 12:17:10 -080078 // 1 argument: check for special cases (-l or --help)
Felipe Lemebbfd2b82016-02-03 11:16:27 -080079 if (strcmp(argv[1], "--help") == 0) {
80 usage();
81 return 0;
82 }
83 if (strcmp(argv[1], "-l") == 0) {
84 showListOnly = true;
85 }
keunyoungcaad5552013-06-13 15:08:51 -070086 }
Felipe Leme859aef62016-02-03 12:17:10 -080087 if (argc == 3) {
88 // 2 arguments: check for special cases (--skip SERVICES)
89 if (strcmp(argv[1], "--skip") == 0) {
90 char* token = strtok(argv[2], ",");
91 while (token != NULL) {
92 skippedServices.add(String16(token));
93 token = strtok(NULL, ",");
94 }
95 }
96 }
97 bool dumpAll = argc == 1;
98 if (dumpAll || !skippedServices.empty() || showListOnly) {
99 // gets all services
Colin Crossf45fa6b2012-03-26 12:38:26 -0700100 services = sm->listServices();
101 services.sort(sort_func);
102 args.add(String16("-a"));
103 } else {
Felipe Leme859aef62016-02-03 12:17:10 -0800104 // gets a specific service:
105 // first check if its name is not a special argument...
106 if (strcmp(argv[1], "--skip") == 0 || strcmp(argv[1], "-l") == 0) {
107 usage();
108 return -1;
109 }
110 // ...then gets its arguments
Colin Crossf45fa6b2012-03-26 12:38:26 -0700111 services.add(String16(argv[1]));
112 for (int i=2; i<argc; i++) {
113 args.add(String16(argv[i]));
114 }
115 }
116
117 const size_t N = services.size();
118
119 if (N > 1) {
120 // first print a list of the current services
121 aout << "Currently running services:" << endl;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800122
Colin Crossf45fa6b2012-03-26 12:38:26 -0700123 for (size_t i=0; i<N; i++) {
124 sp<IBinder> service = sm->checkService(services[i]);
125 if (service != NULL) {
Felipe Leme859aef62016-02-03 12:17:10 -0800126 bool skipped = IsSkipped(skippedServices, services[i]);
127 aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700128 }
129 }
130 }
131
keunyoungcaad5552013-06-13 15:08:51 -0700132 if (showListOnly) {
133 return 0;
134 }
135
Josh Gao4b8f6f92016-02-29 16:20:34 -0800136 for (size_t i = 0; i < N; i++) {
137 String16 service_name = std::move(services[i]);
138 if (IsSkipped(skippedServices, service_name)) continue;
Felipe Leme859aef62016-02-03 12:17:10 -0800139
Josh Gao4b8f6f92016-02-29 16:20:34 -0800140 sp<IBinder> service = sm->checkService(service_name);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700141 if (service != NULL) {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800142 int sfd[2];
143
Josh Gao49f0a0c2016-03-04 13:12:29 -0800144 if (pipe(sfd) != 0) {
145 aerr << "Failed to create pipe to dump service info for " << service_name
Josh Gao4b8f6f92016-02-29 16:20:34 -0800146 << ": " << strerror(errno) << endl;
147 continue;
148 }
149
150 unique_fd local_end(sfd[0]);
151 unique_fd remote_end(sfd[1]);
152 sfd[0] = sfd[1] = -1;
153
Colin Crossf45fa6b2012-03-26 12:38:26 -0700154 if (N > 1) {
155 aout << "------------------------------------------------------------"
156 "-------------------" << endl;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800157 aout << "DUMP OF SERVICE " << service_name << ":" << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700158 }
Josh Gao4b8f6f92016-02-29 16:20:34 -0800159
160 // dump blocks until completion, so spawn a thread..
161 std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {
162 int err = service->dump(remote_end.get(), args);
163
164 // It'd be nice to be able to close the remote end of the socketpair before the dump
165 // call returns, to terminate our reads if the other end closes their copy of the
166 // file descriptor, but then hangs for some reason. There doesn't seem to be a good
167 // way to do this, though.
168 remote_end.clear();
169
170 if (err != 0) {
171 aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
172 << endl;
173 }
174 });
175
176 // TODO: Make this configurable at runtime.
177 constexpr auto timeout = std::chrono::seconds(10);
178 auto end = std::chrono::steady_clock::now() + timeout;
179
180 struct pollfd pfd = {
181 .fd = local_end.get(),
182 .events = POLLIN
183 };
184
185 bool timed_out = false;
186 bool error = false;
187 while (true) {
188 // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
189 auto time_left_ms = [end]() {
190 auto now = std::chrono::steady_clock::now();
191 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
192 return std::max(diff.count(), 0ll);
193 };
194
195 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
196 if (rc < 0) {
197 aerr << "Error in poll while dumping service " << service_name << " : "
198 << strerror(errno) << endl;
199 error = true;
200 break;
201 } else if (rc == 0) {
202 timed_out = true;
203 break;
204 }
205
206 char buf[4096];
207 rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf)));
208 if (rc < 0) {
209 aerr << "Failed to read while dumping service " << service_name << ": "
210 << strerror(errno) << endl;
211 error = true;
212 break;
213 } else if (rc == 0) {
214 // EOF.
215 break;
216 }
217
218 if (!WriteFully(STDOUT_FILENO, buf, rc)) {
219 aerr << "Failed to write while dumping service " << service_name << ": "
220 << strerror(errno) << endl;
221 error = true;
222 break;
223 }
224 }
225
226 if (timed_out) {
227 aout << endl << "*** SERVICE DUMP TIMEOUT EXPIRED ***" << endl << endl;
228 }
229
230 if (timed_out || error) {
231 dump_thread.detach();
232 } else {
233 dump_thread.join();
Colin Crossf45fa6b2012-03-26 12:38:26 -0700234 }
235 } else {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800236 aerr << "Can't find service: " << service_name << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700237 }
238 }
239
240 return 0;
241}