blob: 8fe246b609a256356683199e4d4785dc388ee7d8 [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>
Kevin Rocard430e0792017-08-14 20:40:24 -070019#include <iomanip>
Josh Gao4b8f6f92016-02-29 16:20:34 -080020#include <thread>
21
22#include <android-base/file.h>
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -070023#include <android-base/stringprintf.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080024#include <android-base/unique_fd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070025#include <binder/Parcel.h>
26#include <binder/ProcessState.h>
Mathias Agopian002e1e52013-05-06 20:20:50 -070027#include <binder/TextOutput.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080028#include <utils/Log.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070029#include <utils/Vector.h>
30
Josh Gao4b8f6f92016-02-29 16:20:34 -080031#include <fcntl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070032#include <getopt.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070033#include <stdio.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080034#include <stdlib.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070035#include <string.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080036#include <sys/poll.h>
37#include <sys/socket.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070038#include <sys/time.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080039#include <sys/types.h>
40#include <unistd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070041
Felipe Leme343175a2016-08-02 18:57:37 -070042#include "dumpsys.h"
43
Colin Crossf45fa6b2012-03-26 12:38:26 -070044using namespace android;
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -070045using android::base::StringPrintf;
Josh Gao4b8f6f92016-02-29 16:20:34 -080046using android::base::unique_fd;
47using android::base::WriteFully;
Colin Crossf45fa6b2012-03-26 12:38:26 -070048
Steven Moreland2c3cd832017-02-13 23:44:17 +000049static int sort_func(const String16* lhs, const String16* rhs)
50{
Colin Crossf45fa6b2012-03-26 12:38:26 -070051 return lhs->compare(*rhs);
52}
53
Felipe Lemebbfd2b82016-02-03 11:16:27 -080054static void usage() {
55 fprintf(stderr,
Vishnu Nairf56042d2017-09-19 15:25:10 -070056 "usage: dumpsys\n"
Felipe Lemebbfd2b82016-02-03 11:16:27 -080057 " To dump all services.\n"
58 "or:\n"
Vishnu Nairf56042d2017-09-19 15:25:10 -070059 " dumpsys [-t TIMEOUT] [--priority LEVEL] [--help | -l | --skip SERVICES | "
60 "SERVICE [ARGS]]\n"
Felipe Lemebbfd2b82016-02-03 11:16:27 -080061 " --help: shows this help\n"
62 " -l: only list services, do not dump them\n"
Thierry Strudel8b78b752016-03-22 10:25:44 -070063 " -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
Vishnu Nairf56042d2017-09-19 15:25:10 -070064 " --priority LEVEL: filter services based on specified priority\n"
65 " LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
Felipe Leme859aef62016-02-03 12:17:10 -080066 " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
67 " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
68}
69
Felipe Leme343175a2016-08-02 18:57:37 -070070static bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
Felipe Leme859aef62016-02-03 12:17:10 -080071 for (const auto& candidate : skipped) {
72 if (candidate == service) {
73 return true;
74 }
75 }
76 return false;
Felipe Lemebbfd2b82016-02-03 11:16:27 -080077}
78
Felipe Leme343175a2016-08-02 18:57:37 -070079int Dumpsys::main(int argc, char* const argv[]) {
Colin Crossf45fa6b2012-03-26 12:38:26 -070080 Vector<String16> services;
81 Vector<String16> args;
Felipe Leme859aef62016-02-03 12:17:10 -080082 Vector<String16> skippedServices;
keunyoungcaad5552013-06-13 15:08:51 -070083 bool showListOnly = false;
Thierry Strudel8b78b752016-03-22 10:25:44 -070084 bool skipServices = false;
85 int timeoutArg = 10;
Vishnu Nairf56042d2017-09-19 15:25:10 -070086 int dumpPriority = IServiceManager::DUMP_PRIORITY_ALL;
87 static struct option longOptions[] = {{"priority", required_argument, 0, 0},
88 {"skip", no_argument, 0, 0},
89 {"help", no_argument, 0, 0},
90 {0, 0, 0, 0}};
Thierry Strudel8b78b752016-03-22 10:25:44 -070091
Felipe Leme343175a2016-08-02 18:57:37 -070092 // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
93 // happens on test cases).
94 optind = 1;
Thierry Strudel8b78b752016-03-22 10:25:44 -070095 while (1) {
96 int c;
97 int optionIndex = 0;
98
99 c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex);
100
101 if (c == -1) {
102 break;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800103 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700104
105 switch (c) {
106 case 0:
107 if (!strcmp(longOptions[optionIndex].name, "skip")) {
108 skipServices = true;
109 } else if (!strcmp(longOptions[optionIndex].name, "help")) {
110 usage();
111 return 0;
Vishnu Nairf56042d2017-09-19 15:25:10 -0700112 } else if (!strcmp(longOptions[optionIndex].name, "priority")) {
113 if (!strcmp(optarg, "CRITICAL")) {
114 dumpPriority = IServiceManager::DUMP_PRIORITY_CRITICAL;
115 } else if (!strcmp(optarg, "HIGH")) {
116 dumpPriority = IServiceManager::DUMP_PRIORITY_HIGH;
117 } else if (!strcmp(optarg, "NORMAL")) {
118 dumpPriority = IServiceManager::DUMP_PRIORITY_NORMAL;
119 } else {
120 fprintf(stderr, "\n");
121 usage();
122 return -1;
123 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700124 }
125 break;
126
127 case 't':
128 {
129 char *endptr;
130 timeoutArg = strtol(optarg, &endptr, 10);
131 if (*endptr != '\0' || timeoutArg <= 0) {
132 fprintf(stderr, "Error: invalid timeout number: '%s'\n", optarg);
133 return -1;
134 }
135 }
136 break;
137
138 case 'l':
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800139 showListOnly = true;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700140 break;
141
142 default:
143 fprintf(stderr, "\n");
144 usage();
145 return -1;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800146 }
keunyoungcaad5552013-06-13 15:08:51 -0700147 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700148
149 for (int i = optind; i < argc; i++) {
150 if (skipServices) {
151 skippedServices.add(String16(argv[i]));
152 } else {
153 if (i == optind) {
154 services.add(String16(argv[i]));
155 } else {
156 args.add(String16(argv[i]));
Felipe Leme859aef62016-02-03 12:17:10 -0800157 }
158 }
159 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700160
161 if ((skipServices && skippedServices.empty()) ||
Steven Moreland2c3cd832017-02-13 23:44:17 +0000162 (showListOnly && (!services.empty() || !skippedServices.empty()))) {
Thierry Strudel8b78b752016-03-22 10:25:44 -0700163 usage();
164 return -1;
165 }
166
Thierry Strudel159a8322016-03-23 11:22:34 -0700167 if (services.empty() || showListOnly) {
Felipe Leme859aef62016-02-03 12:17:10 -0800168 // gets all services
Vishnu Nairf56042d2017-09-19 15:25:10 -0700169 services = sm_->listServices(dumpPriority);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700170 services.sort(sort_func);
171 args.add(String16("-a"));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700172 }
173
174 const size_t N = services.size();
175
176 if (N > 1) {
177 // first print a list of the current services
178 aout << "Currently running services:" << endl;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800179
Colin Crossf45fa6b2012-03-26 12:38:26 -0700180 for (size_t i=0; i<N; i++) {
Felipe Leme343175a2016-08-02 18:57:37 -0700181 sp<IBinder> service = sm_->checkService(services[i]);
182
183 if (service != nullptr) {
Felipe Leme859aef62016-02-03 12:17:10 -0800184 bool skipped = IsSkipped(skippedServices, services[i]);
185 aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700186 }
187 }
188 }
189
keunyoungcaad5552013-06-13 15:08:51 -0700190 if (showListOnly) {
191 return 0;
192 }
193
Josh Gao4b8f6f92016-02-29 16:20:34 -0800194 for (size_t i = 0; i < N; i++) {
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -0700195 const String16& service_name = std::move(services[i]);
Josh Gao4b8f6f92016-02-29 16:20:34 -0800196 if (IsSkipped(skippedServices, service_name)) continue;
Felipe Leme859aef62016-02-03 12:17:10 -0800197
Felipe Leme343175a2016-08-02 18:57:37 -0700198 sp<IBinder> service = sm_->checkService(service_name);
199 if (service != nullptr) {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800200 int sfd[2];
201
Josh Gao49f0a0c2016-03-04 13:12:29 -0800202 if (pipe(sfd) != 0) {
203 aerr << "Failed to create pipe to dump service info for " << service_name
Josh Gao4b8f6f92016-02-29 16:20:34 -0800204 << ": " << strerror(errno) << endl;
205 continue;
206 }
207
208 unique_fd local_end(sfd[0]);
209 unique_fd remote_end(sfd[1]);
210 sfd[0] = sfd[1] = -1;
211
Colin Crossf45fa6b2012-03-26 12:38:26 -0700212 if (N > 1) {
213 aout << "------------------------------------------------------------"
214 "-------------------" << endl;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800215 aout << "DUMP OF SERVICE " << service_name << ":" << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700216 }
Josh Gao4b8f6f92016-02-29 16:20:34 -0800217
218 // dump blocks until completion, so spawn a thread..
219 std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {
220 int err = service->dump(remote_end.get(), args);
221
222 // It'd be nice to be able to close the remote end of the socketpair before the dump
223 // call returns, to terminate our reads if the other end closes their copy of the
224 // file descriptor, but then hangs for some reason. There doesn't seem to be a good
225 // way to do this, though.
Josh Gao9656be12016-09-19 12:44:50 -0700226 remote_end.reset();
Josh Gao4b8f6f92016-02-29 16:20:34 -0800227
228 if (err != 0) {
229 aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
230 << endl;
231 }
232 });
233
Thierry Strudel8b78b752016-03-22 10:25:44 -0700234 auto timeout = std::chrono::seconds(timeoutArg);
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700235 auto start = std::chrono::steady_clock::now();
236 auto end = start + timeout;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800237
238 struct pollfd pfd = {
239 .fd = local_end.get(),
240 .events = POLLIN
241 };
242
243 bool timed_out = false;
244 bool error = false;
245 while (true) {
246 // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
247 auto time_left_ms = [end]() {
248 auto now = std::chrono::steady_clock::now();
249 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
250 return std::max(diff.count(), 0ll);
251 };
252
253 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
254 if (rc < 0) {
255 aerr << "Error in poll while dumping service " << service_name << " : "
256 << strerror(errno) << endl;
257 error = true;
258 break;
259 } else if (rc == 0) {
260 timed_out = true;
261 break;
262 }
263
264 char buf[4096];
265 rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf)));
266 if (rc < 0) {
267 aerr << "Failed to read while dumping service " << service_name << ": "
268 << strerror(errno) << endl;
269 error = true;
270 break;
271 } else if (rc == 0) {
272 // EOF.
273 break;
274 }
275
276 if (!WriteFully(STDOUT_FILENO, buf, rc)) {
277 aerr << "Failed to write while dumping service " << service_name << ": "
278 << strerror(errno) << endl;
279 error = true;
280 break;
281 }
282 }
283
284 if (timed_out) {
Felipe Leme343175a2016-08-02 18:57:37 -0700285 aout << endl
286 << "*** SERVICE '" << service_name << "' DUMP TIMEOUT (" << timeoutArg
287 << "s) EXPIRED ***" << endl
288 << endl;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800289 }
290
291 if (timed_out || error) {
292 dump_thread.detach();
293 } else {
294 dump_thread.join();
Colin Crossf45fa6b2012-03-26 12:38:26 -0700295 }
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700296
297 if (N > 1) {
298 std::chrono::duration<double> elapsed_seconds =
299 std::chrono::steady_clock::now() - start;
mukesh agrawalbca287d2016-07-27 12:01:49 -0700300 aout << StringPrintf("--------- %.3fs ", elapsed_seconds.count()).c_str()
Kevin Rocard430e0792017-08-14 20:40:24 -0700301 << "was the duration of dumpsys " << service_name;
302
303 using std::chrono::system_clock;
304 const auto finish = system_clock::to_time_t(system_clock::now());
305 std::tm finish_tm;
306 localtime_r(&finish, &finish_tm);
307 aout << ", ending at: " << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S")
308 << endl;
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700309 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700310 } else {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800311 aerr << "Can't find service: " << service_name << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700312 }
313 }
314
315 return 0;
316}