blob: f0e720006909dd051b9e28f8a305e1121f7330a7 [file] [log] [blame]
Colin Crossf45fa6b2012-03-26 12:38:26 -07001/*
Felipe Leme343175a2016-08-02 18:57:37 -07002 * Copyright (C) 2009 The Android Open Source Project
Colin Crossf45fa6b2012-03-26 12:38:26 -07003 *
Felipe Leme343175a2016-08-02 18:57:37 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Colin Crossf45fa6b2012-03-26 12:38:26 -070015 */
16
Josh Gao4b8f6f92016-02-29 16:20:34 -080017#include <algorithm>
18#include <chrono>
19#include <thread>
20
21#include <android-base/file.h>
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -070022#include <android-base/stringprintf.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080023#include <android-base/unique_fd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070024#include <binder/Parcel.h>
25#include <binder/ProcessState.h>
Mathias Agopian002e1e52013-05-06 20:20:50 -070026#include <binder/TextOutput.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080027#include <utils/Log.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070028#include <utils/Vector.h>
29
Josh Gao4b8f6f92016-02-29 16:20:34 -080030#include <fcntl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070031#include <getopt.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070032#include <stdio.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080033#include <stdlib.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070034#include <string.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080035#include <sys/poll.h>
36#include <sys/socket.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070037#include <sys/time.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080038#include <sys/types.h>
39#include <unistd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070040
Felipe Leme343175a2016-08-02 18:57:37 -070041#include "dumpsys.h"
42
Colin Crossf45fa6b2012-03-26 12:38:26 -070043using namespace android;
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -070044using android::base::StringPrintf;
Josh Gao4b8f6f92016-02-29 16:20:34 -080045using android::base::unique_fd;
46using android::base::WriteFully;
Colin Crossf45fa6b2012-03-26 12:38:26 -070047
Steven Moreland2c3cd832017-02-13 23:44:17 +000048static int sort_func(const String16* lhs, const String16* rhs)
49{
Colin Crossf45fa6b2012-03-26 12:38:26 -070050 return lhs->compare(*rhs);
51}
52
Felipe Lemebbfd2b82016-02-03 11:16:27 -080053static void usage() {
54 fprintf(stderr,
55 "usage: dumpsys\n"
56 " To dump all services.\n"
57 "or:\n"
Steven Moreland2c3cd832017-02-13 23:44:17 +000058 " dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
Felipe Lemebbfd2b82016-02-03 11:16:27 -080059 " --help: shows this help\n"
60 " -l: only list services, do not dump them\n"
Thierry Strudel8b78b752016-03-22 10:25:44 -070061 " -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
Felipe Leme859aef62016-02-03 12:17:10 -080062 " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
63 " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
64}
65
Felipe Leme343175a2016-08-02 18:57:37 -070066static bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
Felipe Leme859aef62016-02-03 12:17:10 -080067 for (const auto& candidate : skipped) {
68 if (candidate == service) {
69 return true;
70 }
71 }
72 return false;
Felipe Lemebbfd2b82016-02-03 11:16:27 -080073}
74
Felipe Leme343175a2016-08-02 18:57:37 -070075int Dumpsys::main(int argc, char* const argv[]) {
Colin Crossf45fa6b2012-03-26 12:38:26 -070076 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
Felipe Leme343175a2016-08-02 18:57:37 -070088 // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
89 // happens on test cases).
90 optind = 1;
Thierry Strudel8b78b752016-03-22 10:25:44 -070091 while (1) {
92 int c;
93 int optionIndex = 0;
94
95 c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex);
96
97 if (c == -1) {
98 break;
Felipe Lemebbfd2b82016-02-03 11:16:27 -080099 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700100
101 switch (c) {
102 case 0:
103 if (!strcmp(longOptions[optionIndex].name, "skip")) {
104 skipServices = true;
105 } else if (!strcmp(longOptions[optionIndex].name, "help")) {
106 usage();
107 return 0;
108 }
109 break;
110
111 case 't':
112 {
113 char *endptr;
114 timeoutArg = strtol(optarg, &endptr, 10);
115 if (*endptr != '\0' || timeoutArg <= 0) {
116 fprintf(stderr, "Error: invalid timeout number: '%s'\n", optarg);
117 return -1;
118 }
119 }
120 break;
121
122 case 'l':
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800123 showListOnly = true;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700124 break;
125
126 default:
127 fprintf(stderr, "\n");
128 usage();
129 return -1;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800130 }
keunyoungcaad5552013-06-13 15:08:51 -0700131 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700132
133 for (int i = optind; i < argc; i++) {
134 if (skipServices) {
135 skippedServices.add(String16(argv[i]));
136 } else {
137 if (i == optind) {
138 services.add(String16(argv[i]));
139 } else {
140 args.add(String16(argv[i]));
Felipe Leme859aef62016-02-03 12:17:10 -0800141 }
142 }
143 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700144
145 if ((skipServices && skippedServices.empty()) ||
Steven Moreland2c3cd832017-02-13 23:44:17 +0000146 (showListOnly && (!services.empty() || !skippedServices.empty()))) {
Thierry Strudel8b78b752016-03-22 10:25:44 -0700147 usage();
148 return -1;
149 }
150
Thierry Strudel159a8322016-03-23 11:22:34 -0700151 if (services.empty() || showListOnly) {
Felipe Leme859aef62016-02-03 12:17:10 -0800152 // gets all services
Felipe Leme343175a2016-08-02 18:57:37 -0700153 services = sm_->listServices();
Colin Crossf45fa6b2012-03-26 12:38:26 -0700154 services.sort(sort_func);
155 args.add(String16("-a"));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700156 }
157
158 const size_t N = services.size();
159
160 if (N > 1) {
161 // first print a list of the current services
162 aout << "Currently running services:" << endl;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800163
Colin Crossf45fa6b2012-03-26 12:38:26 -0700164 for (size_t i=0; i<N; i++) {
Felipe Leme343175a2016-08-02 18:57:37 -0700165 sp<IBinder> service = sm_->checkService(services[i]);
166
167 if (service != nullptr) {
Felipe Leme859aef62016-02-03 12:17:10 -0800168 bool skipped = IsSkipped(skippedServices, services[i]);
169 aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700170 }
171 }
172 }
173
keunyoungcaad5552013-06-13 15:08:51 -0700174 if (showListOnly) {
175 return 0;
176 }
177
Josh Gao4b8f6f92016-02-29 16:20:34 -0800178 for (size_t i = 0; i < N; i++) {
179 String16 service_name = std::move(services[i]);
180 if (IsSkipped(skippedServices, service_name)) continue;
Felipe Leme859aef62016-02-03 12:17:10 -0800181
Felipe Leme343175a2016-08-02 18:57:37 -0700182 sp<IBinder> service = sm_->checkService(service_name);
183 if (service != nullptr) {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800184 int sfd[2];
185
Josh Gao49f0a0c2016-03-04 13:12:29 -0800186 if (pipe(sfd) != 0) {
187 aerr << "Failed to create pipe to dump service info for " << service_name
Josh Gao4b8f6f92016-02-29 16:20:34 -0800188 << ": " << strerror(errno) << endl;
189 continue;
190 }
191
192 unique_fd local_end(sfd[0]);
193 unique_fd remote_end(sfd[1]);
194 sfd[0] = sfd[1] = -1;
195
Colin Crossf45fa6b2012-03-26 12:38:26 -0700196 if (N > 1) {
197 aout << "------------------------------------------------------------"
198 "-------------------" << endl;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800199 aout << "DUMP OF SERVICE " << service_name << ":" << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700200 }
Josh Gao4b8f6f92016-02-29 16:20:34 -0800201
202 // dump blocks until completion, so spawn a thread..
203 std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {
204 int err = service->dump(remote_end.get(), args);
205
206 // It'd be nice to be able to close the remote end of the socketpair before the dump
207 // call returns, to terminate our reads if the other end closes their copy of the
208 // file descriptor, but then hangs for some reason. There doesn't seem to be a good
209 // way to do this, though.
Josh Gao9656be12016-09-19 12:44:50 -0700210 remote_end.reset();
Josh Gao4b8f6f92016-02-29 16:20:34 -0800211
212 if (err != 0) {
213 aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
214 << endl;
215 }
216 });
217
Thierry Strudel8b78b752016-03-22 10:25:44 -0700218 auto timeout = std::chrono::seconds(timeoutArg);
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700219 auto start = std::chrono::steady_clock::now();
220 auto end = start + timeout;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800221
222 struct pollfd pfd = {
223 .fd = local_end.get(),
224 .events = POLLIN
225 };
226
227 bool timed_out = false;
228 bool error = false;
229 while (true) {
230 // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
231 auto time_left_ms = [end]() {
232 auto now = std::chrono::steady_clock::now();
233 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
234 return std::max(diff.count(), 0ll);
235 };
236
237 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
238 if (rc < 0) {
239 aerr << "Error in poll while dumping service " << service_name << " : "
240 << strerror(errno) << endl;
241 error = true;
242 break;
243 } else if (rc == 0) {
244 timed_out = true;
245 break;
246 }
247
248 char buf[4096];
249 rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf)));
250 if (rc < 0) {
251 aerr << "Failed to read while dumping service " << service_name << ": "
252 << strerror(errno) << endl;
253 error = true;
254 break;
255 } else if (rc == 0) {
256 // EOF.
257 break;
258 }
259
260 if (!WriteFully(STDOUT_FILENO, buf, rc)) {
261 aerr << "Failed to write while dumping service " << service_name << ": "
262 << strerror(errno) << endl;
263 error = true;
264 break;
265 }
266 }
267
268 if (timed_out) {
Felipe Leme343175a2016-08-02 18:57:37 -0700269 aout << endl
270 << "*** SERVICE '" << service_name << "' DUMP TIMEOUT (" << timeoutArg
271 << "s) EXPIRED ***" << endl
272 << endl;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800273 }
274
275 if (timed_out || error) {
276 dump_thread.detach();
277 } else {
278 dump_thread.join();
Colin Crossf45fa6b2012-03-26 12:38:26 -0700279 }
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700280
281 if (N > 1) {
282 std::chrono::duration<double> elapsed_seconds =
283 std::chrono::steady_clock::now() - start;
mukesh agrawalbca287d2016-07-27 12:01:49 -0700284 aout << StringPrintf("--------- %.3fs ", elapsed_seconds.count()).c_str()
285 << "was the duration of dumpsys " << service_name << endl;
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700286 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700287 } else {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800288 aerr << "Can't find service: " << service_name << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700289 }
290 }
291
292 return 0;
293}