1/* 2 * Command that dumps interesting system state to the log. 3 * 4 */ 5 6#define LOG_TAG "dumpsys" 7 8#include <algorithm> 9#include <chrono> 10#include <thread> 11 12#include <android-base/file.h> 13#include <android-base/unique_fd.h> 14#include <binder/IServiceManager.h> 15#include <binder/Parcel.h> 16#include <binder/ProcessState.h> 17#include <binder/TextOutput.h> 18#include <utils/Log.h> 19#include <utils/Vector.h> 20 21#include <fcntl.h> 22#include <getopt.h> 23#include <stdio.h> 24#include <stdlib.h> 25#include <string.h> 26#include <sys/poll.h> 27#include <sys/socket.h> 28#include <sys/time.h> 29#include <sys/types.h> 30#include <unistd.h> 31 32using namespace android; 33using android::base::unique_fd; 34using android::base::WriteFully; 35 36static int sort_func(const String16* lhs, const String16* rhs) 37{ 38 return lhs->compare(*rhs); 39} 40 41static void usage() { 42 fprintf(stderr, 43 "usage: dumpsys\n" 44 " To dump all services.\n" 45 "or:\n" 46 " dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n" 47 " --help: shows this help\n" 48 " -l: only list services, do not dump them\n" 49 " -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n" 50 " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n" 51 " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n"); 52} 53 54bool IsSkipped(const Vector<String16>& skipped, const String16& service) { 55 for (const auto& candidate : skipped) { 56 if (candidate == service) { 57 return true; 58 } 59 } 60 return false; 61} 62 63int main(int argc, char* const argv[]) 64{ 65 signal(SIGPIPE, SIG_IGN); 66 sp<IServiceManager> sm = defaultServiceManager(); 67 fflush(stdout); 68 if (sm == NULL) { 69 ALOGE("Unable to get default service manager!"); 70 aerr << "dumpsys: Unable to get default service manager!" << endl; 71 return 20; 72 } 73 74 Vector<String16> services; 75 Vector<String16> args; 76 Vector<String16> skippedServices; 77 bool showListOnly = false; 78 bool skipServices = false; 79 int timeoutArg = 10; 80 static struct option longOptions[] = { 81 {"skip", no_argument, 0, 0 }, 82 {"help", no_argument, 0, 0 }, 83 { 0, 0, 0, 0 } 84 }; 85 86 while (1) { 87 int c; 88 int optionIndex = 0; 89 90 c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex); 91 92 if (c == -1) { 93 break; 94 } 95 96 switch (c) { 97 case 0: 98 if (!strcmp(longOptions[optionIndex].name, "skip")) { 99 skipServices = true; 100 } else if (!strcmp(longOptions[optionIndex].name, "help")) { 101 usage(); 102 return 0; 103 } 104 break; 105 106 case 't': 107 { 108 char *endptr; 109 timeoutArg = strtol(optarg, &endptr, 10); 110 if (*endptr != '\0' || timeoutArg <= 0) { 111 fprintf(stderr, "Error: invalid timeout number: '%s'\n", optarg); 112 return -1; 113 } 114 } 115 break; 116 117 case 'l': 118 showListOnly = true; 119 break; 120 121 default: 122 fprintf(stderr, "\n"); 123 usage(); 124 return -1; 125 } 126 } 127 128 for (int i = optind; i < argc; i++) { 129 if (skipServices) { 130 skippedServices.add(String16(argv[i])); 131 } else { 132 if (i == optind) { 133 services.add(String16(argv[i])); 134 } else { 135 args.add(String16(argv[i])); 136 } 137 } 138 } 139 140 if ((skipServices && skippedServices.empty()) || 141 (showListOnly && (!services.empty() || !skippedServices.empty()))) { 142 usage(); 143 return -1; 144 } 145 146 if (services.empty() || showListOnly) { 147 // gets all services 148 services = sm->listServices(); 149 services.sort(sort_func); 150 args.add(String16("-a")); 151 } 152 153 const size_t N = services.size(); 154 155 if (N > 1) { 156 // first print a list of the current services 157 aout << "Currently running services:" << endl; 158 159 for (size_t i=0; i<N; i++) { 160 sp<IBinder> service = sm->checkService(services[i]); 161 if (service != NULL) { 162 bool skipped = IsSkipped(skippedServices, services[i]); 163 aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl; 164 } 165 } 166 } 167 168 if (showListOnly) { 169 return 0; 170 } 171 172 for (size_t i = 0; i < N; i++) { 173 String16 service_name = std::move(services[i]); 174 if (IsSkipped(skippedServices, service_name)) continue; 175 176 sp<IBinder> service = sm->checkService(service_name); 177 if (service != NULL) { 178 int sfd[2]; 179 180 if (pipe(sfd) != 0) { 181 aerr << "Failed to create pipe to dump service info for " << service_name 182 << ": " << strerror(errno) << endl; 183 continue; 184 } 185 186 unique_fd local_end(sfd[0]); 187 unique_fd remote_end(sfd[1]); 188 sfd[0] = sfd[1] = -1; 189 190 if (N > 1) { 191 aout << "------------------------------------------------------------" 192 "-------------------" << endl; 193 aout << "DUMP OF SERVICE " << service_name << ":" << endl; 194 } 195 196 // dump blocks until completion, so spawn a thread.. 197 std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable { 198 int err = service->dump(remote_end.get(), args); 199 200 // It'd be nice to be able to close the remote end of the socketpair before the dump 201 // call returns, to terminate our reads if the other end closes their copy of the 202 // file descriptor, but then hangs for some reason. There doesn't seem to be a good 203 // way to do this, though. 204 remote_end.clear(); 205 206 if (err != 0) { 207 aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name 208 << endl; 209 } 210 }); 211 212 auto timeout = std::chrono::seconds(timeoutArg); 213 auto end = std::chrono::steady_clock::now() + timeout; 214 215 struct pollfd pfd = { 216 .fd = local_end.get(), 217 .events = POLLIN 218 }; 219 220 bool timed_out = false; 221 bool error = false; 222 while (true) { 223 // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout. 224 auto time_left_ms = [end]() { 225 auto now = std::chrono::steady_clock::now(); 226 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now); 227 return std::max(diff.count(), 0ll); 228 }; 229 230 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms())); 231 if (rc < 0) { 232 aerr << "Error in poll while dumping service " << service_name << " : " 233 << strerror(errno) << endl; 234 error = true; 235 break; 236 } else if (rc == 0) { 237 timed_out = true; 238 break; 239 } 240 241 char buf[4096]; 242 rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf))); 243 if (rc < 0) { 244 aerr << "Failed to read while dumping service " << service_name << ": " 245 << strerror(errno) << endl; 246 error = true; 247 break; 248 } else if (rc == 0) { 249 // EOF. 250 break; 251 } 252 253 if (!WriteFully(STDOUT_FILENO, buf, rc)) { 254 aerr << "Failed to write while dumping service " << service_name << ": " 255 << strerror(errno) << endl; 256 error = true; 257 break; 258 } 259 } 260 261 if (timed_out) { 262 aout << endl << "*** SERVICE DUMP TIMEOUT EXPIRED ***" << endl << endl; 263 } 264 265 if (timed_out || error) { 266 dump_thread.detach(); 267 } else { 268 dump_thread.join(); 269 } 270 } else { 271 aerr << "Can't find service: " << service_name << endl; 272 } 273 } 274 275 return 0; 276} 277