OSDN Git Service

Merge "Fix security vulnerability" into nyc-dev
[android-x86/frameworks-native.git] / cmds / dumpsys / dumpsys.cpp
1 /*
2  * Command that dumps interesting system state to the log.
3  *
4  */
5
6 #define LOG_TAG "dumpsys"
7
8 #include <algorithm>
9 #include <chrono>
10 #include <thread>
11
12 #include <android-base/file.h>
13 #include <android-base/stringprintf.h>
14 #include <android-base/unique_fd.h>
15 #include <binder/IServiceManager.h>
16 #include <binder/Parcel.h>
17 #include <binder/ProcessState.h>
18 #include <binder/TextOutput.h>
19 #include <utils/Log.h>
20 #include <utils/Vector.h>
21
22 #include <fcntl.h>
23 #include <getopt.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/poll.h>
28 #include <sys/socket.h>
29 #include <sys/time.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32
33 using namespace android;
34 using android::base::StringPrintf;
35 using android::base::unique_fd;
36 using android::base::WriteFully;
37
38 static int sort_func(const String16* lhs, const String16* rhs)
39 {
40     return lhs->compare(*rhs);
41 }
42
43 static void usage() {
44     fprintf(stderr,
45         "usage: dumpsys\n"
46             "         To dump all services.\n"
47             "or:\n"
48             "       dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
49             "         --help: shows this help\n"
50             "         -l: only list services, do not dump them\n"
51             "         -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
52             "         --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
56 bool 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;
63 }
64
65 int main(int argc, char* const argv[])
66 {
67     signal(SIGPIPE, SIG_IGN);
68     sp<IServiceManager> sm = defaultServiceManager();
69     fflush(stdout);
70     if (sm == NULL) {
71         ALOGE("Unable to get default service manager!");
72         aerr << "dumpsys: Unable to get default service manager!" << endl;
73         return 20;
74     }
75
76     Vector<String16> services;
77     Vector<String16> args;
78     Vector<String16> skippedServices;
79     bool showListOnly = false;
80     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;
96         }
97
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':
120             showListOnly = true;
121             break;
122
123         default:
124             fprintf(stderr, "\n");
125             usage();
126             return -1;
127         }
128     }
129
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]));
138             }
139         }
140     }
141
142     if ((skipServices && skippedServices.empty()) ||
143             (showListOnly && (!services.empty() || !skippedServices.empty()))) {
144         usage();
145         return -1;
146     }
147
148     if (services.empty() || showListOnly) {
149         // gets all services
150         services = sm->listServices();
151         services.sort(sort_func);
152         args.add(String16("-a"));
153     }
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;
160
161         for (size_t i=0; i<N; i++) {
162             sp<IBinder> service = sm->checkService(services[i]);
163             if (service != NULL) {
164                 bool skipped = IsSkipped(skippedServices, services[i]);
165                 aout << "  " << services[i] << (skipped ? " (skipped)" : "") << endl;
166             }
167         }
168     }
169
170     if (showListOnly) {
171         return 0;
172     }
173
174     for (size_t i = 0; i < N; i++) {
175         String16 service_name = std::move(services[i]);
176         if (IsSkipped(skippedServices, service_name)) continue;
177
178         sp<IBinder> service = sm->checkService(service_name);
179         if (service != NULL) {
180             int sfd[2];
181
182             if (pipe(sfd) != 0) {
183                 aerr << "Failed to create pipe to dump service info for " << service_name
184                      << ": " << 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
192             if (N > 1) {
193                 aout << "------------------------------------------------------------"
194                         "-------------------" << endl;
195                 aout << "DUMP OF SERVICE " << service_name << ":" << endl;
196             }
197
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
214             auto timeout = std::chrono::seconds(timeoutArg);
215             auto start = std::chrono::steady_clock::now();
216             auto end = start + timeout;
217
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();
272             }
273
274             if (N > 1) {
275               std::chrono::duration<double> elapsed_seconds =
276                   std::chrono::steady_clock::now() - start;
277               aout << StringPrintf("--------- %.3fs ", elapsed_seconds.count()).c_str()
278                    << "was the duration of dumpsys " << service_name << endl;
279             }
280         } else {
281             aerr << "Can't find service: " << service_name << endl;
282         }
283     }
284
285     return 0;
286 }