blob: 860b7b42de2da263acad55182835ec1679d09630 [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 Moreland6270dd12017-01-20 15:24:51 -080048static int sort_func(const String16* lhs, const String16* rhs) {
Colin Crossf45fa6b2012-03-26 12:38:26 -070049 return lhs->compare(*rhs);
50}
51
Felipe Lemebbfd2b82016-02-03 11:16:27 -080052static void usage() {
53 fprintf(stderr,
54 "usage: dumpsys\n"
55 " To dump all services.\n"
56 "or:\n"
Steven Moreland6270dd12017-01-20 15:24:51 -080057 " dumpsys [-t TIMEOUT] [--help | --hw | -l | --skip SERVICES | SERVICE [ARGS]]\n"
Felipe Lemebbfd2b82016-02-03 11:16:27 -080058 " --help: shows this help\n"
59 " -l: only list services, do not dump them\n"
Thierry Strudel8b78b752016-03-22 10:25:44 -070060 " -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
Steven Moreland6270dd12017-01-20 15:24:51 -080061 " --hw: list all hw services running on the device\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
Steven Moreland6270dd12017-01-20 15:24:51 -080075static void ListHardwareServices(android::hidl::manager::V1_0::IServiceManager* hm) {
76 using android::hardware::hidl_vec;
77 using android::hardware::hidl_string;
78 using android::hardware::Return;
79 using android::sp;
80
81 if (hm == nullptr) {
82 ALOGE("Unable to get hardware service manager!");
83 aerr << "Failed to get hardware service manager!";
84 return;
85 }
86
87 Return<void> ret = hm->list([](const hidl_vec<hidl_string> &registered){
88 aout << "Currently running hardware services:" << endl;
89 for (const auto &service : registered) {
90 aout << " " << service << endl;
91 }
92 });
93
94 if (!ret.isOk()) {
95 aerr << "Failed to list hardware services: " << ret.description();
96 }
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;
Felipe Leme859aef62016-02-03 12:17:10 -0800102 Vector<String16> skippedServices;
keunyoungcaad5552013-06-13 15:08:51 -0700103 bool showListOnly = false;
Steven Moreland6270dd12017-01-20 15:24:51 -0800104 bool listHwOnly = false;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700105 bool skipServices = false;
106 int timeoutArg = 10;
107 static struct option longOptions[] = {
108 {"skip", no_argument, 0, 0 },
109 {"help", no_argument, 0, 0 },
Steven Moreland6270dd12017-01-20 15:24:51 -0800110 {"hw", no_argument, 0, 0 },
Thierry Strudel8b78b752016-03-22 10:25:44 -0700111 { 0, 0, 0, 0 }
112 };
113
Felipe Leme343175a2016-08-02 18:57:37 -0700114 // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
115 // happens on test cases).
116 optind = 1;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700117 while (1) {
118 int c;
119 int optionIndex = 0;
120
121 c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex);
122
123 if (c == -1) {
124 break;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800125 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700126
127 switch (c) {
128 case 0:
129 if (!strcmp(longOptions[optionIndex].name, "skip")) {
130 skipServices = true;
131 } else if (!strcmp(longOptions[optionIndex].name, "help")) {
132 usage();
133 return 0;
Steven Moreland6270dd12017-01-20 15:24:51 -0800134 } else if (!strcmp(longOptions[optionIndex].name, "hw")) {
135 listHwOnly = true;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700136 }
137 break;
138
139 case 't':
140 {
141 char *endptr;
142 timeoutArg = strtol(optarg, &endptr, 10);
143 if (*endptr != '\0' || timeoutArg <= 0) {
144 fprintf(stderr, "Error: invalid timeout number: '%s'\n", optarg);
145 return -1;
146 }
147 }
148 break;
149
150 case 'l':
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800151 showListOnly = true;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700152 break;
153
154 default:
155 fprintf(stderr, "\n");
156 usage();
157 return -1;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800158 }
keunyoungcaad5552013-06-13 15:08:51 -0700159 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700160
161 for (int i = optind; i < argc; i++) {
162 if (skipServices) {
163 skippedServices.add(String16(argv[i]));
164 } else {
165 if (i == optind) {
166 services.add(String16(argv[i]));
167 } else {
168 args.add(String16(argv[i]));
Felipe Leme859aef62016-02-03 12:17:10 -0800169 }
170 }
171 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700172
173 if ((skipServices && skippedServices.empty()) ||
Steven Moreland6270dd12017-01-20 15:24:51 -0800174 (showListOnly && (!services.empty() || !skippedServices.empty())) ||
175 (listHwOnly && (skipServices || services.size() > 0 || showListOnly))) {
Thierry Strudel8b78b752016-03-22 10:25:44 -0700176 usage();
177 return -1;
178 }
179
Steven Moreland6270dd12017-01-20 15:24:51 -0800180 if (listHwOnly) {
181 ListHardwareServices(hm_);
182 return 0;
183 }
184
Thierry Strudel159a8322016-03-23 11:22:34 -0700185 if (services.empty() || showListOnly) {
Felipe Leme859aef62016-02-03 12:17:10 -0800186 // gets all services
Felipe Leme343175a2016-08-02 18:57:37 -0700187 services = sm_->listServices();
Colin Crossf45fa6b2012-03-26 12:38:26 -0700188 services.sort(sort_func);
189 args.add(String16("-a"));
Colin Crossf45fa6b2012-03-26 12:38:26 -0700190 }
191
192 const size_t N = services.size();
193
194 if (N > 1) {
195 // first print a list of the current services
196 aout << "Currently running services:" << endl;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800197
Colin Crossf45fa6b2012-03-26 12:38:26 -0700198 for (size_t i=0; i<N; i++) {
Felipe Leme343175a2016-08-02 18:57:37 -0700199 sp<IBinder> service = sm_->checkService(services[i]);
200
201 if (service != nullptr) {
Felipe Leme859aef62016-02-03 12:17:10 -0800202 bool skipped = IsSkipped(skippedServices, services[i]);
203 aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700204 }
205 }
206 }
207
keunyoungcaad5552013-06-13 15:08:51 -0700208 if (showListOnly) {
209 return 0;
210 }
211
Josh Gao4b8f6f92016-02-29 16:20:34 -0800212 for (size_t i = 0; i < N; i++) {
213 String16 service_name = std::move(services[i]);
214 if (IsSkipped(skippedServices, service_name)) continue;
Felipe Leme859aef62016-02-03 12:17:10 -0800215
Felipe Leme343175a2016-08-02 18:57:37 -0700216 sp<IBinder> service = sm_->checkService(service_name);
217 if (service != nullptr) {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800218 int sfd[2];
219
Josh Gao49f0a0c2016-03-04 13:12:29 -0800220 if (pipe(sfd) != 0) {
221 aerr << "Failed to create pipe to dump service info for " << service_name
Josh Gao4b8f6f92016-02-29 16:20:34 -0800222 << ": " << strerror(errno) << endl;
223 continue;
224 }
225
226 unique_fd local_end(sfd[0]);
227 unique_fd remote_end(sfd[1]);
228 sfd[0] = sfd[1] = -1;
229
Colin Crossf45fa6b2012-03-26 12:38:26 -0700230 if (N > 1) {
231 aout << "------------------------------------------------------------"
232 "-------------------" << endl;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800233 aout << "DUMP OF SERVICE " << service_name << ":" << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700234 }
Josh Gao4b8f6f92016-02-29 16:20:34 -0800235
236 // dump blocks until completion, so spawn a thread..
237 std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {
238 int err = service->dump(remote_end.get(), args);
239
240 // It'd be nice to be able to close the remote end of the socketpair before the dump
241 // call returns, to terminate our reads if the other end closes their copy of the
242 // file descriptor, but then hangs for some reason. There doesn't seem to be a good
243 // way to do this, though.
Josh Gao9656be12016-09-19 12:44:50 -0700244 remote_end.reset();
Josh Gao4b8f6f92016-02-29 16:20:34 -0800245
246 if (err != 0) {
247 aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
248 << endl;
249 }
250 });
251
Thierry Strudel8b78b752016-03-22 10:25:44 -0700252 auto timeout = std::chrono::seconds(timeoutArg);
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700253 auto start = std::chrono::steady_clock::now();
254 auto end = start + timeout;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800255
256 struct pollfd pfd = {
257 .fd = local_end.get(),
258 .events = POLLIN
259 };
260
261 bool timed_out = false;
262 bool error = false;
263 while (true) {
264 // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
265 auto time_left_ms = [end]() {
266 auto now = std::chrono::steady_clock::now();
267 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
268 return std::max(diff.count(), 0ll);
269 };
270
271 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
272 if (rc < 0) {
273 aerr << "Error in poll while dumping service " << service_name << " : "
274 << strerror(errno) << endl;
275 error = true;
276 break;
277 } else if (rc == 0) {
278 timed_out = true;
279 break;
280 }
281
282 char buf[4096];
283 rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf)));
284 if (rc < 0) {
285 aerr << "Failed to read while dumping service " << service_name << ": "
286 << strerror(errno) << endl;
287 error = true;
288 break;
289 } else if (rc == 0) {
290 // EOF.
291 break;
292 }
293
294 if (!WriteFully(STDOUT_FILENO, buf, rc)) {
295 aerr << "Failed to write while dumping service " << service_name << ": "
296 << strerror(errno) << endl;
297 error = true;
298 break;
299 }
300 }
301
302 if (timed_out) {
Felipe Leme343175a2016-08-02 18:57:37 -0700303 aout << endl
304 << "*** SERVICE '" << service_name << "' DUMP TIMEOUT (" << timeoutArg
305 << "s) EXPIRED ***" << endl
306 << endl;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800307 }
308
309 if (timed_out || error) {
310 dump_thread.detach();
311 } else {
312 dump_thread.join();
Colin Crossf45fa6b2012-03-26 12:38:26 -0700313 }
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700314
315 if (N > 1) {
316 std::chrono::duration<double> elapsed_seconds =
317 std::chrono::steady_clock::now() - start;
mukesh agrawalbca287d2016-07-27 12:01:49 -0700318 aout << StringPrintf("--------- %.3fs ", elapsed_seconds.count()).c_str()
319 << "was the duration of dumpsys " << service_name << endl;
mukesh agrawal2f1eb1c2016-06-08 18:16:36 -0700320 }
Colin Crossf45fa6b2012-03-26 12:38:26 -0700321 } else {
Josh Gao4b8f6f92016-02-29 16:20:34 -0800322 aerr << "Can't find service: " << service_name << endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700323 }
324 }
325
326 return 0;
327}