2 * Command that dumps interesting system state to the log.
6 #define LOG_TAG "dumpsys"
12 #include <android-base/file.h>
13 #include <android-base/unique_fd.h>
14 #include <binder/IServiceManager.h>
15 #include <binder/Parcel.h>
16 #include <binder/ProcessState.h>
17 #include <binder/TextOutput.h>
18 #include <utils/Log.h>
19 #include <utils/Vector.h>
27 #include <sys/socket.h>
29 #include <sys/types.h>
32 using namespace android;
33 using android::base::unique_fd;
34 using android::base::WriteFully;
36 static int sort_func(const String16* lhs, const String16* rhs)
38 return lhs->compare(*rhs);
44 " To dump all services.\n"
46 " dumpsys [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
47 " --help: shows this help\n"
48 " -l: only list services, do not dump them\n"
49 " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
50 " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
53 bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
54 for (const auto& candidate : skipped) {
55 if (candidate == service) {
62 int main(int argc, char* const argv[])
64 signal(SIGPIPE, SIG_IGN);
65 sp<IServiceManager> sm = defaultServiceManager();
68 ALOGE("Unable to get default service manager!");
69 aerr << "dumpsys: Unable to get default service manager!" << endl;
73 Vector<String16> services;
74 Vector<String16> args;
75 Vector<String16> skippedServices;
76 bool showListOnly = false;
78 // 1 argument: check for special cases (-l or --help)
79 if (strcmp(argv[1], "--help") == 0) {
83 if (strcmp(argv[1], "-l") == 0) {
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, ",");
97 bool dumpAll = argc == 1;
98 if (dumpAll || !skippedServices.empty() || showListOnly) {
100 services = sm->listServices();
101 services.sort(sort_func);
102 args.add(String16("-a"));
104 // 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) {
110 // ...then gets its arguments
111 services.add(String16(argv[1]));
112 for (int i=2; i<argc; i++) {
113 args.add(String16(argv[i]));
117 const size_t N = services.size();
120 // first print a list of the current services
121 aout << "Currently running services:" << endl;
123 for (size_t i=0; i<N; i++) {
124 sp<IBinder> service = sm->checkService(services[i]);
125 if (service != NULL) {
126 bool skipped = IsSkipped(skippedServices, services[i]);
127 aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl;
136 for (size_t i = 0; i < N; i++) {
137 String16 service_name = std::move(services[i]);
138 if (IsSkipped(skippedServices, service_name)) continue;
140 sp<IBinder> service = sm->checkService(service_name);
141 if (service != NULL) {
144 if (pipe(sfd) != 0) {
145 aerr << "Failed to create pipe to dump service info for " << service_name
146 << ": " << strerror(errno) << endl;
150 unique_fd local_end(sfd[0]);
151 unique_fd remote_end(sfd[1]);
152 sfd[0] = sfd[1] = -1;
155 aout << "------------------------------------------------------------"
156 "-------------------" << endl;
157 aout << "DUMP OF SERVICE " << service_name << ":" << endl;
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);
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.
171 aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
176 // TODO: Make this configurable at runtime.
177 constexpr auto timeout = std::chrono::seconds(10);
178 auto end = std::chrono::steady_clock::now() + timeout;
180 struct pollfd pfd = {
181 .fd = local_end.get(),
185 bool timed_out = false;
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);
195 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
197 aerr << "Error in poll while dumping service " << service_name << " : "
198 << strerror(errno) << endl;
201 } else if (rc == 0) {
207 rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf)));
209 aerr << "Failed to read while dumping service " << service_name << ": "
210 << strerror(errno) << endl;
213 } else if (rc == 0) {
218 if (!WriteFully(STDOUT_FILENO, buf, rc)) {
219 aerr << "Failed to write while dumping service " << service_name << ": "
220 << strerror(errno) << endl;
227 aout << endl << "*** SERVICE DUMP TIMEOUT EXPIRED ***" << endl << endl;
230 if (timed_out || error) {
231 dump_thread.detach();
236 aerr << "Can't find service: " << service_name << endl;