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