dumpsys.cpp revision 49f0a0cddbcad9be1d408425ee608ca925c6885b
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 [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n" 47 " --help: shows this help\n" 48 " -l: only list services, do not dump them\n" 49 " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n" 50 " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n"); 51} 52 53bool IsSkipped(const Vector<String16>& skipped, const String16& service) { 54 for (const auto& candidate : skipped) { 55 if (candidate == service) { 56 return true; 57 } 58 } 59 return false; 60} 61 62int main(int argc, char* const argv[]) 63{ 64 signal(SIGPIPE, SIG_IGN); 65 sp<IServiceManager> sm = defaultServiceManager(); 66 fflush(stdout); 67 if (sm == NULL) { 68 ALOGE("Unable to get default service manager!"); 69 aerr << "dumpsys: Unable to get default service manager!" << endl; 70 return 20; 71 } 72 73 Vector<String16> services; 74 Vector<String16> args; 75 Vector<String16> skippedServices; 76 bool showListOnly = false; 77 if (argc == 2) { 78 // 1 argument: check for special cases (-l or --help) 79 if (strcmp(argv[1], "--help") == 0) { 80 usage(); 81 return 0; 82 } 83 if (strcmp(argv[1], "-l") == 0) { 84 showListOnly = true; 85 } 86 } 87 if (argc == 3) { 88 // 2 arguments: check for special cases (--skip SERVICES) 89 if (strcmp(argv[1], "--skip") == 0) { 90 char* token = strtok(argv[2], ","); 91 while (token != NULL) { 92 skippedServices.add(String16(token)); 93 token = strtok(NULL, ","); 94 } 95 } 96 } 97 bool dumpAll = argc == 1; 98 if (dumpAll || !skippedServices.empty() || showListOnly) { 99 // gets all services 100 services = sm->listServices(); 101 services.sort(sort_func); 102 args.add(String16("-a")); 103 } else { 104 // gets a specific service: 105 // first check if its name is not a special argument... 106 if (strcmp(argv[1], "--skip") == 0 || strcmp(argv[1], "-l") == 0) { 107 usage(); 108 return -1; 109 } 110 // ...then gets its arguments 111 services.add(String16(argv[1])); 112 for (int i=2; i<argc; i++) { 113 args.add(String16(argv[i])); 114 } 115 } 116 117 const size_t N = services.size(); 118 119 if (N > 1) { 120 // first print a list of the current services 121 aout << "Currently running services:" << endl; 122 123 for (size_t i=0; i<N; i++) { 124 sp<IBinder> service = sm->checkService(services[i]); 125 if (service != NULL) { 126 bool skipped = IsSkipped(skippedServices, services[i]); 127 aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl; 128 } 129 } 130 } 131 132 if (showListOnly) { 133 return 0; 134 } 135 136 for (size_t i = 0; i < N; i++) { 137 String16 service_name = std::move(services[i]); 138 if (IsSkipped(skippedServices, service_name)) continue; 139 140 sp<IBinder> service = sm->checkService(service_name); 141 if (service != NULL) { 142 int sfd[2]; 143 144 if (pipe(sfd) != 0) { 145 aerr << "Failed to create pipe to dump service info for " << service_name 146 << ": " << strerror(errno) << endl; 147 continue; 148 } 149 150 unique_fd local_end(sfd[0]); 151 unique_fd remote_end(sfd[1]); 152 sfd[0] = sfd[1] = -1; 153 154 if (N > 1) { 155 aout << "------------------------------------------------------------" 156 "-------------------" << endl; 157 aout << "DUMP OF SERVICE " << service_name << ":" << endl; 158 } 159 160 // dump blocks until completion, so spawn a thread.. 161 std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable { 162 int err = service->dump(remote_end.get(), args); 163 164 // It'd be nice to be able to close the remote end of the socketpair before the dump 165 // call returns, to terminate our reads if the other end closes their copy of the 166 // file descriptor, but then hangs for some reason. There doesn't seem to be a good 167 // way to do this, though. 168 remote_end.clear(); 169 170 if (err != 0) { 171 aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name 172 << endl; 173 } 174 }); 175 176 // TODO: Make this configurable at runtime. 177 constexpr auto timeout = std::chrono::seconds(10); 178 auto end = std::chrono::steady_clock::now() + timeout; 179 180 struct pollfd pfd = { 181 .fd = local_end.get(), 182 .events = POLLIN 183 }; 184 185 bool timed_out = false; 186 bool error = false; 187 while (true) { 188 // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout. 189 auto time_left_ms = [end]() { 190 auto now = std::chrono::steady_clock::now(); 191 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now); 192 return std::max(diff.count(), 0ll); 193 }; 194 195 int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms())); 196 if (rc < 0) { 197 aerr << "Error in poll while dumping service " << service_name << " : " 198 << strerror(errno) << endl; 199 error = true; 200 break; 201 } else if (rc == 0) { 202 timed_out = true; 203 break; 204 } 205 206 char buf[4096]; 207 rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf))); 208 if (rc < 0) { 209 aerr << "Failed to read while dumping service " << service_name << ": " 210 << strerror(errno) << endl; 211 error = true; 212 break; 213 } else if (rc == 0) { 214 // EOF. 215 break; 216 } 217 218 if (!WriteFully(STDOUT_FILENO, buf, rc)) { 219 aerr << "Failed to write while dumping service " << service_name << ": " 220 << strerror(errno) << endl; 221 error = true; 222 break; 223 } 224 } 225 226 if (timed_out) { 227 aout << endl << "*** SERVICE DUMP TIMEOUT EXPIRED ***" << endl << endl; 228 } 229 230 if (timed_out || error) { 231 dump_thread.detach(); 232 } else { 233 dump_thread.join(); 234 } 235 } else { 236 aerr << "Can't find service: " << service_name << endl; 237 } 238 } 239 240 return 0; 241} 242