blob: 3d2bdf1d6f45166f8528a60e3b1a1a38b6db15ad [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>
Devin Mooredef9fae2021-08-05 19:05:45 +000024#include <android-base/strings.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080025#include <android-base/unique_fd.h>
Devin Mooredef9fae2021-08-05 19:05:45 +000026#include <binder/BpBinder.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070027#include <binder/Parcel.h>
28#include <binder/ProcessState.h>
Steven Morelande5a6a872021-05-19 22:11:37 +000029#include <binder/Stability.h>
Mathias Agopian002e1e52013-05-06 20:20:50 -070030#include <binder/TextOutput.h>
Devin Moorecfeeda42020-12-08 12:50:58 -080031#include <binderdebug/BinderDebug.h>
Vishnu Nair780b1282017-10-10 13:57:24 -070032#include <serviceutils/PriorityDumper.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080033#include <utils/Log.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070034#include <utils/Vector.h>
35
Steven Moreland3657ee52020-01-31 12:09:15 -080036#include <iostream>
Josh Gao4b8f6f92016-02-29 16:20:34 -080037#include <fcntl.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070038#include <getopt.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070039#include <stdio.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080040#include <stdlib.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070041#include <string.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080042#include <sys/poll.h>
43#include <sys/socket.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070044#include <sys/time.h>
Josh Gao4b8f6f92016-02-29 16:20:34 -080045#include <sys/types.h>
46#include <unistd.h>
Colin Crossf45fa6b2012-03-26 12:38:26 -070047
Felipe Leme343175a2016-08-02 18:57:37 -070048#include "dumpsys.h"
49
Colin Crossf45fa6b2012-03-26 12:38:26 -070050using namespace android;
Vishnu Naire4f61742017-12-21 08:30:28 -080051using ::android::base::StringAppendF;
52using ::android::base::StringPrintf;
53using ::android::base::unique_fd;
54using ::android::base::WriteFully;
55using ::android::base::WriteStringToFd;
Colin Crossf45fa6b2012-03-26 12:38:26 -070056
Steven Moreland2c3cd832017-02-13 23:44:17 +000057static int sort_func(const String16* lhs, const String16* rhs)
58{
Colin Crossf45fa6b2012-03-26 12:38:26 -070059 return lhs->compare(*rhs);
60}
61
Felipe Lemebbfd2b82016-02-03 11:16:27 -080062static void usage() {
Devin Mooredef9fae2021-08-05 19:05:45 +000063 fprintf(
64 stderr,
65 "usage: dumpsys\n"
66 " To dump all services.\n"
67 "or:\n"
68 " dumpsys [-t TIMEOUT] [--priority LEVEL] [--clients] [--dump] [--pid] [--thread] "
69 "[--help | "
70 "-l | --skip SERVICES "
71 "| SERVICE [ARGS]]\n"
72 " --help: shows this help\n"
73 " -l: only list services, do not dump them\n"
74 " -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
75 " -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
76 " --clients: dump client PIDs instead of usual dump\n"
77 " --dump: ask the service to dump itself (this is the default)\n"
78 " --pid: dump PID instead of usual dump\n"
79 " --proto: filter services that support dumping data in proto format. Dumps\n"
80 " will be in proto format.\n"
81 " --priority LEVEL: filter services based on specified priority\n"
82 " LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
83 " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
84 " --stability: dump binder stability information instead of usual dump\n"
85 " --thread: dump thread usage instead of usual dump\n"
86 " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
Felipe Leme859aef62016-02-03 12:17:10 -080087}
88
Felipe Leme343175a2016-08-02 18:57:37 -070089static bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
Felipe Leme859aef62016-02-03 12:17:10 -080090 for (const auto& candidate : skipped) {
91 if (candidate == service) {
92 return true;
93 }
94 }
95 return false;
Felipe Lemebbfd2b82016-02-03 11:16:27 -080096}
97
Vishnu Nair6a408532017-10-24 09:11:27 -070098static bool ConvertPriorityTypeToBitmask(const String16& type, int& bitmask) {
99 if (type == PriorityDumper::PRIORITY_ARG_CRITICAL) {
100 bitmask = IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL;
Vishnu Nair780b1282017-10-10 13:57:24 -0700101 return true;
102 }
Vishnu Nair6a408532017-10-24 09:11:27 -0700103 if (type == PriorityDumper::PRIORITY_ARG_HIGH) {
104 bitmask = IServiceManager::DUMP_FLAG_PRIORITY_HIGH;
Vishnu Nair780b1282017-10-10 13:57:24 -0700105 return true;
106 }
Vishnu Nair6a408532017-10-24 09:11:27 -0700107 if (type == PriorityDumper::PRIORITY_ARG_NORMAL) {
108 bitmask = IServiceManager::DUMP_FLAG_PRIORITY_NORMAL;
Vishnu Nair780b1282017-10-10 13:57:24 -0700109 return true;
110 }
111 return false;
112}
113
Vishnu Naire4f61742017-12-21 08:30:28 -0800114String16 ConvertBitmaskToPriorityType(int bitmask) {
115 if (bitmask == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
116 return String16(PriorityDumper::PRIORITY_ARG_CRITICAL);
117 }
118 if (bitmask == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
119 return String16(PriorityDumper::PRIORITY_ARG_HIGH);
120 }
121 if (bitmask == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) {
122 return String16(PriorityDumper::PRIORITY_ARG_NORMAL);
123 }
124 return String16("");
125}
126
Felipe Leme343175a2016-08-02 18:57:37 -0700127int Dumpsys::main(int argc, char* const argv[]) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700128 Vector<String16> services;
129 Vector<String16> args;
Vishnu Nair780b1282017-10-10 13:57:24 -0700130 String16 priorityType;
Felipe Leme859aef62016-02-03 12:17:10 -0800131 Vector<String16> skippedServices;
Vishnu Nair6a408532017-10-24 09:11:27 -0700132 Vector<String16> protoServices;
keunyoungcaad5552013-06-13 15:08:51 -0700133 bool showListOnly = false;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700134 bool skipServices = false;
Vishnu Naire4f61742017-12-21 08:30:28 -0800135 bool asProto = false;
Steven Morelandcbd69fc2021-07-20 20:45:43 +0000136 int dumpTypeFlags = 0;
Vishnu Nair6921f802017-11-22 09:17:23 -0800137 int timeoutArgMs = 10000;
Vishnu Naire4f61742017-12-21 08:30:28 -0800138 int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
Devin Mooredef9fae2021-08-05 19:05:45 +0000139 static struct option longOptions[] = {
140 {"help", no_argument, 0, 0}, {"clients", no_argument, 0, 0},
141 {"dump", no_argument, 0, 0}, {"pid", no_argument, 0, 0},
142 {"priority", required_argument, 0, 0}, {"proto", no_argument, 0, 0},
143 {"skip", no_argument, 0, 0}, {"stability", no_argument, 0, 0},
144 {"thread", no_argument, 0, 0}, {0, 0, 0, 0}};
Thierry Strudel8b78b752016-03-22 10:25:44 -0700145
Felipe Leme343175a2016-08-02 18:57:37 -0700146 // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
147 // happens on test cases).
148 optind = 1;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700149 while (1) {
150 int c;
151 int optionIndex = 0;
152
Vishnu Nair6921f802017-11-22 09:17:23 -0800153 c = getopt_long(argc, argv, "+t:T:l", longOptions, &optionIndex);
Thierry Strudel8b78b752016-03-22 10:25:44 -0700154
155 if (c == -1) {
156 break;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800157 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700158
159 switch (c) {
160 case 0:
161 if (!strcmp(longOptions[optionIndex].name, "skip")) {
162 skipServices = true;
Vishnu Nair6a408532017-10-24 09:11:27 -0700163 } else if (!strcmp(longOptions[optionIndex].name, "proto")) {
Vishnu Naire4f61742017-12-21 08:30:28 -0800164 asProto = true;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700165 } else if (!strcmp(longOptions[optionIndex].name, "help")) {
166 usage();
167 return 0;
Vishnu Nairf56042d2017-09-19 15:25:10 -0700168 } else if (!strcmp(longOptions[optionIndex].name, "priority")) {
Vishnu Nair780b1282017-10-10 13:57:24 -0700169 priorityType = String16(String8(optarg));
Vishnu Naire4f61742017-12-21 08:30:28 -0800170 if (!ConvertPriorityTypeToBitmask(priorityType, priorityFlags)) {
Vishnu Nairf56042d2017-09-19 15:25:10 -0700171 fprintf(stderr, "\n");
172 usage();
173 return -1;
174 }
Steven Morelandcbd69fc2021-07-20 20:45:43 +0000175 } else if (!strcmp(longOptions[optionIndex].name, "dump")) {
176 dumpTypeFlags |= TYPE_DUMP;
Steven Moreland5a30d342019-10-08 13:53:28 -0700177 } else if (!strcmp(longOptions[optionIndex].name, "pid")) {
Steven Morelandcbd69fc2021-07-20 20:45:43 +0000178 dumpTypeFlags |= TYPE_PID;
Steven Morelande5a6a872021-05-19 22:11:37 +0000179 } else if (!strcmp(longOptions[optionIndex].name, "stability")) {
Steven Morelandcbd69fc2021-07-20 20:45:43 +0000180 dumpTypeFlags |= TYPE_STABILITY;
Devin Moorecfeeda42020-12-08 12:50:58 -0800181 } else if (!strcmp(longOptions[optionIndex].name, "thread")) {
Steven Morelandcbd69fc2021-07-20 20:45:43 +0000182 dumpTypeFlags |= TYPE_THREAD;
Devin Mooredef9fae2021-08-05 19:05:45 +0000183 } else if (!strcmp(longOptions[optionIndex].name, "clients")) {
184 dumpTypeFlags |= TYPE_CLIENTS;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700185 }
186 break;
187
188 case 't':
189 {
Vishnu Nair6921f802017-11-22 09:17:23 -0800190 char* endptr;
191 timeoutArgMs = strtol(optarg, &endptr, 10);
192 timeoutArgMs = timeoutArgMs * 1000;
193 if (*endptr != '\0' || timeoutArgMs <= 0) {
194 fprintf(stderr, "Error: invalid timeout(seconds) number: '%s'\n", optarg);
195 return -1;
196 }
197 }
198 break;
199
200 case 'T':
201 {
202 char* endptr;
203 timeoutArgMs = strtol(optarg, &endptr, 10);
204 if (*endptr != '\0' || timeoutArgMs <= 0) {
205 fprintf(stderr, "Error: invalid timeout(milliseconds) number: '%s'\n", optarg);
Thierry Strudel8b78b752016-03-22 10:25:44 -0700206 return -1;
207 }
208 }
209 break;
210
211 case 'l':
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800212 showListOnly = true;
Thierry Strudel8b78b752016-03-22 10:25:44 -0700213 break;
214
215 default:
216 fprintf(stderr, "\n");
217 usage();
218 return -1;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800219 }
keunyoungcaad5552013-06-13 15:08:51 -0700220 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700221
Steven Morelandcbd69fc2021-07-20 20:45:43 +0000222 if (dumpTypeFlags == 0) {
223 dumpTypeFlags = TYPE_DUMP;
224 }
225
Thierry Strudel8b78b752016-03-22 10:25:44 -0700226 for (int i = optind; i < argc; i++) {
227 if (skipServices) {
228 skippedServices.add(String16(argv[i]));
229 } else {
230 if (i == optind) {
231 services.add(String16(argv[i]));
232 } else {
Riddle Hsuc66abb22019-09-27 16:10:21 +0800233 const String16 arg(argv[i]);
234 args.add(arg);
235 // For backward compatible, if the proto argument is passed to the service, the
236 // dump request is also considered to use proto.
237 if (!asProto && !arg.compare(String16(PriorityDumper::PROTO_ARG))) {
238 asProto = true;
239 }
Felipe Leme859aef62016-02-03 12:17:10 -0800240 }
241 }
242 }
Thierry Strudel8b78b752016-03-22 10:25:44 -0700243
244 if ((skipServices && skippedServices.empty()) ||
Steven Moreland2c3cd832017-02-13 23:44:17 +0000245 (showListOnly && (!services.empty() || !skippedServices.empty()))) {
Thierry Strudel8b78b752016-03-22 10:25:44 -0700246 usage();
247 return -1;
248 }
249
Thierry Strudel159a8322016-03-23 11:22:34 -0700250 if (services.empty() || showListOnly) {
Vishnu Naire4f61742017-12-21 08:30:28 -0800251 services = listServices(priorityFlags, asProto);
252 setServiceArgs(args, asProto, priorityFlags);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700253 }
254
255 const size_t N = services.size();
Steven Moreland31dac352020-03-05 09:46:45 -0800256 if (N > 1 || showListOnly) {
Colin Crossf45fa6b2012-03-26 12:38:26 -0700257 // first print a list of the current services
Steven Moreland3657ee52020-01-31 12:09:15 -0800258 std::cout << "Currently running services:" << std::endl;
Felipe Lemebbfd2b82016-02-03 11:16:27 -0800259
Colin Crossf45fa6b2012-03-26 12:38:26 -0700260 for (size_t i=0; i<N; i++) {
Felipe Leme343175a2016-08-02 18:57:37 -0700261 sp<IBinder> service = sm_->checkService(services[i]);
262
263 if (service != nullptr) {
Felipe Leme859aef62016-02-03 12:17:10 -0800264 bool skipped = IsSkipped(skippedServices, services[i]);
Steven Moreland3657ee52020-01-31 12:09:15 -0800265 std::cout << " " << services[i] << (skipped ? " (skipped)" : "") << std::endl;
Colin Crossf45fa6b2012-03-26 12:38:26 -0700266 }
267 }
268 }
269
keunyoungcaad5552013-06-13 15:08:51 -0700270 if (showListOnly) {
271 return 0;
272 }
273
Josh Gao4b8f6f92016-02-29 16:20:34 -0800274 for (size_t i = 0; i < N; i++) {
Vishnu Naire4f61742017-12-21 08:30:28 -0800275 const String16& serviceName = services[i];
276 if (IsSkipped(skippedServices, serviceName)) continue;
Felipe Leme859aef62016-02-03 12:17:10 -0800277
Steven Morelandcbd69fc2021-07-20 20:45:43 +0000278 if (startDumpThread(dumpTypeFlags, serviceName, args) == OK) {
Vishnu Naire4f61742017-12-21 08:30:28 -0800279 bool addSeparator = (N > 1);
280 if (addSeparator) {
281 writeDumpHeader(STDOUT_FILENO, serviceName, priorityFlags);
Josh Gao4b8f6f92016-02-29 16:20:34 -0800282 }
Vishnu Naire4f61742017-12-21 08:30:28 -0800283 std::chrono::duration<double> elapsedDuration;
284 size_t bytesWritten = 0;
285 status_t status =
286 writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(timeoutArgMs),
287 asProto, elapsedDuration, bytesWritten);
Josh Gao4b8f6f92016-02-29 16:20:34 -0800288
Vishnu Naire4f61742017-12-21 08:30:28 -0800289 if (status == TIMED_OUT) {
Steven Moreland3657ee52020-01-31 12:09:15 -0800290 std::cout << std::endl
Vishnu Naire4f61742017-12-21 08:30:28 -0800291 << "*** SERVICE '" << serviceName << "' DUMP TIMEOUT (" << timeoutArgMs
Steven Moreland3657ee52020-01-31 12:09:15 -0800292 << "ms) EXPIRED ***" << std::endl
293 << std::endl;
Josh Gao4b8f6f92016-02-29 16:20:34 -0800294 }
295
Vishnu Naire4f61742017-12-21 08:30:28 -0800296 if (addSeparator) {
297 writeDumpFooter(STDOUT_FILENO, serviceName, elapsedDuration);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700298 }
Vishnu Naire4f61742017-12-21 08:30:28 -0800299 bool dumpComplete = (status == OK);
300 stopDumpThread(dumpComplete);
Colin Crossf45fa6b2012-03-26 12:38:26 -0700301 }
302 }
303
304 return 0;
305}
Vishnu Naire4f61742017-12-21 08:30:28 -0800306
307Vector<String16> Dumpsys::listServices(int priorityFilterFlags, bool filterByProto) const {
308 Vector<String16> services = sm_->listServices(priorityFilterFlags);
309 services.sort(sort_func);
310 if (filterByProto) {
311 Vector<String16> protoServices = sm_->listServices(IServiceManager::DUMP_FLAG_PROTO);
312 protoServices.sort(sort_func);
313 Vector<String16> intersection;
314 std::set_intersection(services.begin(), services.end(), protoServices.begin(),
315 protoServices.end(), std::back_inserter(intersection));
316 services = std::move(intersection);
317 }
318 return services;
319}
320
Vishnu Naire97d6122018-01-18 13:58:56 -0800321void Dumpsys::setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags) {
Vishnu Nair64afc022018-02-01 15:29:34 -0800322 // Add proto flag if dumping service as proto.
Vishnu Naire4f61742017-12-21 08:30:28 -0800323 if (asProto) {
324 args.insertAt(String16(PriorityDumper::PROTO_ARG), 0);
325 }
Vishnu Nair64afc022018-02-01 15:29:34 -0800326
327 // Add -a (dump all) flag if dumping all services, dumping normal services or
328 // services not explicitly registered to a priority bucket (default services).
329 if ((priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL) ||
330 (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) ||
331 (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT)) {
332 args.insertAt(String16("-a"), 0);
333 }
334
335 // Add priority flags when dumping services registered to a specific priority bucket.
336 if ((priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) ||
337 (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) ||
338 (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL)) {
Vishnu Naire4f61742017-12-21 08:30:28 -0800339 String16 priorityType = ConvertBitmaskToPriorityType(priorityFlags);
340 args.insertAt(String16(PriorityDumper::PRIORITY_ARG), 0);
341 args.insertAt(priorityType, 1);
342 }
343}
344
Steven Morelandcbd69fc2021-07-20 20:45:43 +0000345static status_t dumpPidToFd(const sp<IBinder>& service, const unique_fd& fd, bool exclusive) {
Steven Moreland5a30d342019-10-08 13:53:28 -0700346 pid_t pid;
347 status_t status = service->getDebugPid(&pid);
348 if (status != OK) {
349 return status;
350 }
Steven Morelandcbd69fc2021-07-20 20:45:43 +0000351 if (!exclusive) {
352 WriteStringToFd("Service host process PID: ", fd.get());
353 }
Steven Moreland5a30d342019-10-08 13:53:28 -0700354 WriteStringToFd(std::to_string(pid) + "\n", fd.get());
355 return OK;
356}
357
Steven Morelande5a6a872021-05-19 22:11:37 +0000358static status_t dumpStabilityToFd(const sp<IBinder>& service, const unique_fd& fd) {
Steven Morelandcbd69fc2021-07-20 20:45:43 +0000359 WriteStringToFd("Stability: " + internal::Stability::debugToString(service) + "\n", fd);
Steven Morelande5a6a872021-05-19 22:11:37 +0000360 return OK;
361}
362
Devin Moorecfeeda42020-12-08 12:50:58 -0800363static status_t dumpThreadsToFd(const sp<IBinder>& service, const unique_fd& fd) {
364 pid_t pid;
365 status_t status = service->getDebugPid(&pid);
366 if (status != OK) {
367 return status;
368 }
369 BinderPidInfo pidInfo;
370 status = getBinderPidInfo(BinderDebugContext::BINDER, pid, &pidInfo);
371 if (status != OK) {
372 return status;
373 }
374 WriteStringToFd("Threads in use: " + std::to_string(pidInfo.threadUsage) + "/" +
375 std::to_string(pidInfo.threadCount) + "\n",
376 fd.get());
377 return OK;
378}
379
Devin Mooredef9fae2021-08-05 19:05:45 +0000380static status_t dumpClientsToFd(const sp<IBinder>& service, const unique_fd& fd) {
381 std::string clientPids;
382 const auto remoteBinder = service->remoteBinder();
383 if (remoteBinder == nullptr) {
384 WriteStringToFd("Client PIDs are not available for local binders.\n", fd.get());
385 return OK;
386 }
387 const auto handle = remoteBinder->getDebugBinderHandle();
388 if (handle == std::nullopt) {
389 return OK;
390 }
391 std::vector<pid_t> pids;
392 pid_t myPid = getpid();
393 pid_t servicePid;
394 status_t status = service->getDebugPid(&servicePid);
395 if (status != OK) {
396 return status;
397 }
398 status =
399 getBinderClientPids(BinderDebugContext::BINDER, myPid, servicePid, handle.value(), &pids);
400 if (status != OK) {
401 return status;
402 }
403 pids.erase(std::remove_if(pids.begin(), pids.end(), [&](pid_t pid) { return pid == myPid; }),
404 pids.end());
405 WriteStringToFd("Client PIDs: " + ::android::base::Join(pids, ", ") + "\n", fd.get());
406 return OK;
407}
408
Steven Morelandcbd69fc2021-07-20 20:45:43 +0000409static void reportDumpError(const String16& serviceName, status_t error, const char* context) {
410 if (error == OK) return;
411
412 std::cerr << "Error with service '" << serviceName << "' while " << context << ": "
413 << statusToString(error) << std::endl;
414}
415
416status_t Dumpsys::startDumpThread(int dumpTypeFlags, const String16& serviceName,
Steven Moreland5a30d342019-10-08 13:53:28 -0700417 const Vector<String16>& args) {
Vishnu Naire4f61742017-12-21 08:30:28 -0800418 sp<IBinder> service = sm_->checkService(serviceName);
419 if (service == nullptr) {
Steven Moreland3657ee52020-01-31 12:09:15 -0800420 std::cerr << "Can't find service: " << serviceName << std::endl;
Vishnu Naire4f61742017-12-21 08:30:28 -0800421 return NAME_NOT_FOUND;
422 }
423
424 int sfd[2];
425 if (pipe(sfd) != 0) {
Steven Moreland3657ee52020-01-31 12:09:15 -0800426 std::cerr << "Failed to create pipe to dump service info for " << serviceName << ": "
427 << strerror(errno) << std::endl;
Vishnu Naire4f61742017-12-21 08:30:28 -0800428 return -errno;
429 }
430
431 redirectFd_ = unique_fd(sfd[0]);
432 unique_fd remote_end(sfd[1]);
433 sfd[0] = sfd[1] = -1;
434
435 // dump blocks until completion, so spawn a thread..
436 activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable {
Steven Morelandcbd69fc2021-07-20 20:45:43 +0000437 if (dumpTypeFlags & TYPE_PID) {
438 status_t err = dumpPidToFd(service, remote_end, dumpTypeFlags == TYPE_PID);
439 reportDumpError(serviceName, err, "dumping PID");
440 }
441 if (dumpTypeFlags & TYPE_STABILITY) {
442 status_t err = dumpStabilityToFd(service, remote_end);
443 reportDumpError(serviceName, err, "dumping stability");
444 }
445 if (dumpTypeFlags & TYPE_THREAD) {
446 status_t err = dumpThreadsToFd(service, remote_end);
447 reportDumpError(serviceName, err, "dumping thread info");
Steven Moreland5a30d342019-10-08 13:53:28 -0700448 }
Devin Mooredef9fae2021-08-05 19:05:45 +0000449 if (dumpTypeFlags & TYPE_CLIENTS) {
450 status_t err = dumpClientsToFd(service, remote_end);
451 reportDumpError(serviceName, err, "dumping clients info");
452 }
Steven Moreland5a30d342019-10-08 13:53:28 -0700453
Steven Morelandcbd69fc2021-07-20 20:45:43 +0000454 // other types always act as a header, this is usually longer
455 if (dumpTypeFlags & TYPE_DUMP) {
456 status_t err = service->dump(remote_end.get(), args);
457 reportDumpError(serviceName, err, "dumping");
Vishnu Naire4f61742017-12-21 08:30:28 -0800458 }
459 });
460 return OK;
461}
462
463void Dumpsys::stopDumpThread(bool dumpComplete) {
464 if (dumpComplete) {
465 activeThread_.join();
466 } else {
467 activeThread_.detach();
468 }
469 /* close read end of the dump output redirection pipe */
470 redirectFd_.reset();
471}
472
473void Dumpsys::writeDumpHeader(int fd, const String16& serviceName, int priorityFlags) const {
474 std::string msg(
475 "----------------------------------------"
476 "---------------------------------------\n");
477 if (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL ||
Vishnu Nair64afc022018-02-01 15:29:34 -0800478 priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL ||
479 priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
Vishnu Naire4f61742017-12-21 08:30:28 -0800480 StringAppendF(&msg, "DUMP OF SERVICE %s:\n", String8(serviceName).c_str());
481 } else {
482 String16 priorityType = ConvertBitmaskToPriorityType(priorityFlags);
483 StringAppendF(&msg, "DUMP OF SERVICE %s %s:\n", String8(priorityType).c_str(),
484 String8(serviceName).c_str());
485 }
486 WriteStringToFd(msg, fd);
487}
488
489status_t Dumpsys::writeDump(int fd, const String16& serviceName, std::chrono::milliseconds timeout,
490 bool asProto, std::chrono::duration<double>& elapsedDuration,
491 size_t& bytesWritten) const {
492 status_t status = OK;
493 size_t totalBytes = 0;
494 auto start = std::chrono::steady_clock::now();
495 auto end = start + timeout;
496
497 int serviceDumpFd = redirectFd_.get();
498 if (serviceDumpFd == -1) {
499 return INVALID_OPERATION;
500 }
501
502 struct pollfd pfd = {.fd = serviceDumpFd, .events = POLLIN};
503
504 while (true) {
505 // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
506 auto time_left_ms = [end]() {
507 auto now = std::chrono::steady_clock::now();
508 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
Chih-Hung Hsieh9f2d5312018-12-11 15:34:17 -0800509 return std::max(diff.count(), 0LL);
Vishnu Naire4f61742017-12-21 08:30:28 -0800510 };
511
512 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
513 if (rc < 0) {
Steven Moreland3657ee52020-01-31 12:09:15 -0800514 std::cerr << "Error in poll while dumping service " << serviceName << " : "
515 << strerror(errno) << std::endl;
Vishnu Naire4f61742017-12-21 08:30:28 -0800516 status = -errno;
517 break;
Rhed Jaoa19145f2020-12-22 20:42:34 +0800518 } else if (rc == 0 || time_left_ms() == 0) {
Vishnu Naire4f61742017-12-21 08:30:28 -0800519 status = TIMED_OUT;
520 break;
521 }
522
523 char buf[4096];
524 rc = TEMP_FAILURE_RETRY(read(redirectFd_.get(), buf, sizeof(buf)));
525 if (rc < 0) {
Steven Moreland3657ee52020-01-31 12:09:15 -0800526 std::cerr << "Failed to read while dumping service " << serviceName << ": "
527 << strerror(errno) << std::endl;
Vishnu Naire4f61742017-12-21 08:30:28 -0800528 status = -errno;
529 break;
530 } else if (rc == 0) {
531 // EOF.
532 break;
533 }
534
535 if (!WriteFully(fd, buf, rc)) {
Steven Moreland3657ee52020-01-31 12:09:15 -0800536 std::cerr << "Failed to write while dumping service " << serviceName << ": "
537 << strerror(errno) << std::endl;
Vishnu Naire4f61742017-12-21 08:30:28 -0800538 status = -errno;
539 break;
540 }
541 totalBytes += rc;
542 }
543
544 if ((status == TIMED_OUT) && (!asProto)) {
545 std::string msg = StringPrintf("\n*** SERVICE '%s' DUMP TIMEOUT (%llums) EXPIRED ***\n\n",
546 String8(serviceName).string(), timeout.count());
547 WriteStringToFd(msg, fd);
548 }
549
550 elapsedDuration = std::chrono::steady_clock::now() - start;
551 bytesWritten = totalBytes;
552 return status;
553}
554
555void Dumpsys::writeDumpFooter(int fd, const String16& serviceName,
556 const std::chrono::duration<double>& elapsedDuration) const {
557 using std::chrono::system_clock;
558 const auto finish = system_clock::to_time_t(system_clock::now());
559 std::tm finish_tm;
560 localtime_r(&finish, &finish_tm);
561 std::stringstream oss;
562 oss << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S");
563 std::string msg =
564 StringPrintf("--------- %.3fs was the duration of dumpsys %s, ending at: %s\n",
565 elapsedDuration.count(), String8(serviceName).string(), oss.str().c_str());
566 WriteStringToFd(msg, fd);
567}