blob: 0862a40734714e4f9215f86cc46cdf77807763ad [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>
Vishnu Nair780b1282017-10-10 13:57:24 -070028#include <serviceutils/PriorityDumper.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080029#include <utils/Log.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070030#include <utils/Vector.h>
31
Josh Gao4b8f6f92016-02-29 16:20:34 -080032#include <fcntl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070033#include <getopt.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070034#include <stdio.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080035#include <stdlib.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070036#include <string.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080037#include <sys/poll.h>
38#include <sys/socket.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070039#include <sys/time.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080040#include <sys/types.h>
41#include <unistd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070042
Felipe Leme343175a2016-08-02 18:57:37 -070043#include "dumpsys.h"
44
Colin Crossf45fa6b2012-03-26 12:38:26 -070045using namespace android;
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -070046using android::base::StringPrintf;
Josh Gao4b8f6f92016-02-29 16:20:34 -080047using android::base::unique_fd;
48using android::base::WriteFully;
Colin Crossf45fa6b2012-03-26 12:38:26 -070049
Steven Moreland2c3cd832017-02-13 23:44:17 +000050static int sort_func(const String16* lhs, const String16* rhs)
51{
Colin Crossf45fa6b2012-03-26 12:38:26 -070052 return lhs->compare(*rhs);
53}
54
Felipe Lemebbfd2b82016-02-03 11:16:27 -080055static void usage() {
56 fprintf(stderr,
Vishnu Nairf56042d2017-09-19 15:25:10 -070057 "usage: dumpsys\n"
Felipe Lemebbfd2b82016-02-03 11:16:27 -080058 " To dump all services.\n"
59 "or:\n"
Vishnu Nairf56042d2017-09-19 15:25:10 -070060 " dumpsys [-t TIMEOUT] [--priority LEVEL] [--help | -l | --skip SERVICES | "
61 "SERVICE [ARGS]]\n"
Felipe Lemebbfd2b82016-02-03 11:16:27 -080062 " --help: shows this help\n"
63 " -l: only list services, do not dump them\n"
Vishnu Nair6921f802017-11-22 09:17:23 -080064 " -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
65 " -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
Vishnu Nair6a408532017-10-24 09:11:27 -070066 " --proto: filter services that support dumping data in proto format. Dumps"
67 " will be in proto format.\n"
Vishnu Nairf56042d2017-09-19 15:25:10 -070068 " --priority LEVEL: filter services based on specified priority\n"
69 " LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
Felipe Leme859aef62016-02-03 12:17:10 -080070 " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
71 " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
72}
73
Felipe Leme343175a2016-08-02 18:57:37 -070074static bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
Felipe Leme859aef62016-02-03 12:17:10 -080075 for (const auto& candidate : skipped) {
76 if (candidate == service) {
77 return true;
78 }
79 }
80 return false;
Felipe Lemebbfd2b82016-02-03 11:16:27 -080081}
82
Vishnu Nair6a408532017-10-24 09:11:27 -070083static bool ConvertPriorityTypeToBitmask(const String16& type, int& bitmask) {
84 if (type == PriorityDumper::PRIORITY_ARG_CRITICAL) {
85 bitmask = IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL;
Vishnu Nair780b1282017-10-10 13:57:24 -070086 return true;
87 }
Vishnu Nair6a408532017-10-24 09:11:27 -070088 if (type == PriorityDumper::PRIORITY_ARG_HIGH) {
89 bitmask = IServiceManager::DUMP_FLAG_PRIORITY_HIGH;
Vishnu Nair780b1282017-10-10 13:57:24 -070090 return true;
91 }
Vishnu Nair6a408532017-10-24 09:11:27 -070092 if (type == PriorityDumper::PRIORITY_ARG_NORMAL) {
93 bitmask = IServiceManager::DUMP_FLAG_PRIORITY_NORMAL;
Vishnu Nair780b1282017-10-10 13:57:24 -070094 return true;
95 }
96 return false;
97}
98
Felipe Leme343175a2016-08-02 18:57:37 -070099int Dumpsys::main(int argc, char* const argv[]) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700100 Vector<String16> services;
101 Vector<String16> args;
Vishnu Nair780b1282017-10-10 13:57:24 -0700102 String16 priorityType;
Felipe Leme859aef62016-02-03 12:17:10 -0800103 Vector<String16> skippedServices;
Vishnu Nair6a408532017-10-24 09:11:27 -0700104 Vector<String16> protoServices;
keunyoungcaad5552013-06-13 15:08:51 -0700105 bool showListOnly = false;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700106 bool skipServices = false;
Vishnu Nair6a408532017-10-24 09:11:27 -0700107 bool filterByProto = false;
Vishnu Nair6921f802017-11-22 09:17:23 -0800108 int timeoutArgMs = 10000;
Vishnu Nair6a408532017-10-24 09:11:27 -0700109 int dumpPriorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
Vishnu Nairf56042d2017-09-19 15:25:10 -0700110 static struct option longOptions[] = {{"priority", required_argument, 0, 0},
Vishnu Nair6a408532017-10-24 09:11:27 -0700111 {"proto", no_argument, 0, 0},
Vishnu Nairf56042d2017-09-19 15:25:10 -0700112 {"skip", no_argument, 0, 0},
113 {"help", no_argument, 0, 0},
114 {0, 0, 0, 0}};
Thierry Strudel8b78b752016-03-22 10:25:44 -0700115
Felipe Leme343175a2016-08-02 18:57:37 -0700116 // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
117 // happens on test cases).
118 optind = 1;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700119 while (1) {
120 int c;
121 int optionIndex = 0;
122
Vishnu Nair6921f802017-11-22 09:17:23 -0800123 c = getopt_long(argc, argv, "+t:T:l", longOptions, &optionIndex);
Thierry Strudel8b78b752016-03-22 10:25:44 -0700124
125 if (c == -1) {
126 break;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800127 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700128
129 switch (c) {
130 case 0:
131 if (!strcmp(longOptions[optionIndex].name, "skip")) {
132 skipServices = true;
Vishnu Nair6a408532017-10-24 09:11:27 -0700133 } else if (!strcmp(longOptions[optionIndex].name, "proto")) {
134 filterByProto = true;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700135 } else if (!strcmp(longOptions[optionIndex].name, "help")) {
136 usage();
137 return 0;
Vishnu Nairf56042d2017-09-19 15:25:10 -0700138 } else if (!strcmp(longOptions[optionIndex].name, "priority")) {
Vishnu Nair780b1282017-10-10 13:57:24 -0700139 priorityType = String16(String8(optarg));
Vishnu Nair6a408532017-10-24 09:11:27 -0700140 if (!ConvertPriorityTypeToBitmask(priorityType, dumpPriorityFlags)) {
Vishnu Nairf56042d2017-09-19 15:25:10 -0700141 fprintf(stderr, "\n");
142 usage();
143 return -1;
144 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700145 }
146 break;
147
148 case 't':
149 {
Vishnu Nair6921f802017-11-22 09:17:23 -0800150 char* endptr;
151 timeoutArgMs = strtol(optarg, &endptr, 10);
152 timeoutArgMs = timeoutArgMs * 1000;
153 if (*endptr != '\0' || timeoutArgMs <= 0) {
154 fprintf(stderr, "Error: invalid timeout(seconds) number: '%s'\n", optarg);
155 return -1;
156 }
157 }
158 break;
159
160 case 'T':
161 {
162 char* endptr;
163 timeoutArgMs = strtol(optarg, &endptr, 10);
164 if (*endptr != '\0' || timeoutArgMs <= 0) {
165 fprintf(stderr, "Error: invalid timeout(milliseconds) number: '%s'\n", optarg);
Thierry Strudel8b78b752016-03-22 10:25:44 -0700166 return -1;
167 }
168 }
169 break;
170
171 case 'l':
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800172 showListOnly = true;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700173 break;
174
175 default:
176 fprintf(stderr, "\n");
177 usage();
178 return -1;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800179 }
keunyoungcaad5552013-06-13 15:08:51 -0700180 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700181
182 for (int i = optind; i < argc; i++) {
183 if (skipServices) {
184 skippedServices.add(String16(argv[i]));
185 } else {
186 if (i == optind) {
187 services.add(String16(argv[i]));
188 } else {
189 args.add(String16(argv[i]));
Felipe Leme859aef62016-02-03 12:17:10 -0800190 }
191 }
192 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700193
194 if ((skipServices && skippedServices.empty()) ||
Steven Moreland2c3cd832017-02-13 23:44:17 +0000195 (showListOnly && (!services.empty() || !skippedServices.empty()))) {
Thierry Strudel8b78b752016-03-22 10:25:44 -0700196 usage();
197 return -1;
198 }
199
Thierry Strudel159a8322016-03-23 11:22:34 -0700200 if (services.empty() || showListOnly) {
Felipe Leme859aef62016-02-03 12:17:10 -0800201 // gets all services
Vishnu Nair6a408532017-10-24 09:11:27 -0700202 services = sm_->listServices(dumpPriorityFlags);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700203 services.sort(sort_func);
Vishnu Nair6a408532017-10-24 09:11:27 -0700204 if (filterByProto) {
205 protoServices = sm_->listServices(IServiceManager::DUMP_FLAG_PROTO);
206 protoServices.sort(sort_func);
207 Vector<String16> intersection;
208 std::set_intersection(services.begin(), services.end(), protoServices.begin(),
209 protoServices.end(), std::back_inserter(intersection));
210 services = std::move(intersection);
211 args.insertAt(String16(PriorityDumper::PROTO_ARG), 0);
212 }
213 if (dumpPriorityFlags != IServiceManager::DUMP_FLAG_PRIORITY_ALL) {
214 args.insertAt(String16(PriorityDumper::PRIORITY_ARG), 0);
Vishnu Nair780b1282017-10-10 13:57:24 -0700215 args.insertAt(priorityType, 1);
216 } else {
217 args.add(String16("-a"));
218 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700219 }
220
221 const size_t N = services.size();
222
223 if (N > 1) {
224 // first print a list of the current services
225 aout << "Currently running services:" << endl;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800226
Colin Crossf45fa6b2012-03-26 12:38:26 -0700227 for (size_t i=0; i<N; i++) {
Felipe Leme343175a2016-08-02 18:57:37 -0700228 sp<IBinder> service = sm_->checkService(services[i]);
229
230 if (service != nullptr) {
Felipe Leme859aef62016-02-03 12:17:10 -0800231 bool skipped = IsSkipped(skippedServices, services[i]);
232 aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700233 }
234 }
235 }
236
keunyoungcaad5552013-06-13 15:08:51 -0700237 if (showListOnly) {
238 return 0;
239 }
240
Josh Gao4b8f6f92016-02-29 16:20:34 -0800241 for (size_t i = 0; i < N; i++) {
Chih-Hung Hsiehcb057c22017-08-03 15:48:25 -0700242 const String16& service_name = std::move(services[i]);
Josh Gao4b8f6f92016-02-29 16:20:34 -0800243 if (IsSkipped(skippedServices, service_name)) continue;
Felipe Leme859aef62016-02-03 12:17:10 -0800244
Felipe Leme343175a2016-08-02 18:57:37 -0700245 sp<IBinder> service = sm_->checkService(service_name);
246 if (service != nullptr) {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800247 int sfd[2];
248
Josh Gao49f0a0c2016-03-04 13:12:29 -0800249 if (pipe(sfd) != 0) {
250 aerr << "Failed to create pipe to dump service info for " << service_name
Josh Gao4b8f6f92016-02-29 16:20:34 -0800251 << ": " << strerror(errno) << endl;
252 continue;
253 }
254
255 unique_fd local_end(sfd[0]);
256 unique_fd remote_end(sfd[1]);
257 sfd[0] = sfd[1] = -1;
258
Colin Crossf45fa6b2012-03-26 12:38:26 -0700259 if (N > 1) {
260 aout << "------------------------------------------------------------"
261 "-------------------" << endl;
Vishnu Nair6a408532017-10-24 09:11:27 -0700262 if (dumpPriorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL) {
Vishnu Nair780b1282017-10-10 13:57:24 -0700263 aout << "DUMP OF SERVICE " << service_name << ":" << endl;
264 } else {
265 aout << "DUMP OF SERVICE " << priorityType << " " << service_name << ":" << endl;
266 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700267 }
Josh Gao4b8f6f92016-02-29 16:20:34 -0800268
269 // dump blocks until completion, so spawn a thread..
270 std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {
271 int err = service->dump(remote_end.get(), args);
272
273 // It'd be nice to be able to close the remote end of the socketpair before the dump
274 // call returns, to terminate our reads if the other end closes their copy of the
275 // file descriptor, but then hangs for some reason. There doesn't seem to be a good
276 // way to do this, though.
Josh Gao9656be12016-09-19 12:44:50 -0700277 remote_end.reset();
Josh Gao4b8f6f92016-02-29 16:20:34 -0800278
279 if (err != 0) {
280 aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
281 << endl;
282 }
283 });
284
Vishnu Nair6921f802017-11-22 09:17:23 -0800285 auto timeout = std::chrono::milliseconds(timeoutArgMs);
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700286 auto start = std::chrono::steady_clock::now();
287 auto end = start + timeout;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800288
289 struct pollfd pfd = {
290 .fd = local_end.get(),
291 .events = POLLIN
292 };
293
294 bool timed_out = false;
295 bool error = false;
296 while (true) {
297 // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
298 auto time_left_ms = [end]() {
299 auto now = std::chrono::steady_clock::now();
300 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
301 return std::max(diff.count(), 0ll);
302 };
303
304 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
305 if (rc < 0) {
306 aerr << "Error in poll while dumping service " << service_name << " : "
307 << strerror(errno) << endl;
308 error = true;
309 break;
310 } else if (rc == 0) {
311 timed_out = true;
312 break;
313 }
314
315 char buf[4096];
316 rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf)));
317 if (rc < 0) {
318 aerr << "Failed to read while dumping service " << service_name << ": "
319 << strerror(errno) << endl;
320 error = true;
321 break;
322 } else if (rc == 0) {
323 // EOF.
324 break;
325 }
326
327 if (!WriteFully(STDOUT_FILENO, buf, rc)) {
328 aerr << "Failed to write while dumping service " << service_name << ": "
329 << strerror(errno) << endl;
330 error = true;
331 break;
332 }
333 }
334
335 if (timed_out) {
Felipe Leme343175a2016-08-02 18:57:37 -0700336 aout << endl
Vishnu Nair6921f802017-11-22 09:17:23 -0800337 << "*** SERVICE '" << service_name << "' DUMP TIMEOUT (" << timeoutArgMs
338 << "ms) EXPIRED ***" << endl
Felipe Leme343175a2016-08-02 18:57:37 -0700339 << endl;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800340 }
341
342 if (timed_out || error) {
343 dump_thread.detach();
344 } else {
345 dump_thread.join();
Colin Crossf45fa6b2012-03-26 12:38:26 -0700346 }
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700347
348 if (N > 1) {
349 std::chrono::duration<double> elapsed_seconds =
350 std::chrono::steady_clock::now() - start;
mukesh agrawalbca287d2016-07-27 12:01:49 -0700351 aout << StringPrintf("--------- %.3fs ", elapsed_seconds.count()).c_str()
Kevin Rocard430e0792017-08-14 20:40:24 -0700352 << "was the duration of dumpsys " << service_name;
353
354 using std::chrono::system_clock;
355 const auto finish = system_clock::to_time_t(system_clock::now());
356 std::tm finish_tm;
357 localtime_r(&finish, &finish_tm);
358 aout << ", ending at: " << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S")
359 << endl;
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700360 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700361 } else {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800362 aerr << "Can't find service: " << service_name << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700363 }
364 }
365
366 return 0;
367}