1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * 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. 15 */ 16 17 #define LOG_TAG "ProcessCallStack" 18 // #define LOG_NDEBUG 0 19 20 #include <utils/ProcessCallStack.h> 21 22 #include <dirent.h> 23 #include <unistd.h> 24 25 #include <memory> 26 27 #include <utils/Printer.h> 28 29 namespace android { 30 31 enum { 32 // Max sizes for various dynamically generated strings 33 MAX_TIME_STRING = 64, 34 MAX_PROC_PATH = 1024, 35 36 // Dump related prettiness constants 37 IGNORE_DEPTH_CURRENT_THREAD = 2, 38 }; 39 40 static const char* CALL_STACK_PREFIX = " "; 41 static const char* PATH_THREAD_NAME = "/proc/self/task/%d/comm"; 42 static const char* PATH_SELF_TASK = "/proc/self/task"; 43 44 static void dumpProcessHeader(Printer& printer, pid_t pid, const char* timeStr) { 45 if (timeStr == NULL) { 46 ALOGW("%s: timeStr was NULL", __FUNCTION__); 47 return; 48 } 49 50 char path[PATH_MAX]; 51 char procNameBuf[MAX_PROC_PATH]; 52 char* procName = NULL; 53 FILE* fp; 54 55 snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); 56 if ((fp = fopen(path, "r"))) { 57 procName = fgets(procNameBuf, sizeof(procNameBuf), fp); 58 fclose(fp); 59 } 60 61 if (!procName) { 62 procName = const_cast<char*>("<unknown>"); 63 } 64 65 printer.printLine(); 66 printer.printLine(); 67 printer.printFormatLine("----- pid %d at %s -----", pid, timeStr); 68 printer.printFormatLine("Cmd line: %s", procName); 69 } 70 71 static void dumpProcessFooter(Printer& printer, pid_t pid) { 72 printer.printLine(); 73 printer.printFormatLine("----- end %d -----", pid); 74 printer.printLine(); 75 } 76 77 static String8 getThreadName(pid_t tid) { 78 char path[PATH_MAX]; 79 char* procName = NULL; 80 char procNameBuf[MAX_PROC_PATH]; 81 FILE* fp; 82 83 snprintf(path, sizeof(path), PATH_THREAD_NAME, tid); 84 if ((fp = fopen(path, "r"))) { 85 procName = fgets(procNameBuf, sizeof(procNameBuf), fp); 86 fclose(fp); 87 } else { 88 ALOGE("%s: Failed to open %s", __FUNCTION__, path); 89 } 90 91 if (procName == NULL) { 92 // Reading /proc/self/task/%d/comm failed due to a race 93 return String8::format("[err-unknown-tid-%d]", tid); 94 } 95 96 // Strip ending newline 97 strtok(procName, "\n"); 98 99 return String8(procName); 100 } 101 102 static String8 getTimeString(struct tm tm) { 103 char timestr[MAX_TIME_STRING]; 104 // i.e. '2013-10-22 14:42:05' 105 strftime(timestr, sizeof(timestr), "%F %T", &tm); 106 107 return String8(timestr); 108 } 109 110 /* 111 * Implementation of ProcessCallStack 112 */ 113 ProcessCallStack::ProcessCallStack() { 114 } 115 116 ProcessCallStack::ProcessCallStack(const ProcessCallStack& rhs) : 117 mThreadMap(rhs.mThreadMap), 118 mTimeUpdated(rhs.mTimeUpdated) { 119 } 120 121 ProcessCallStack::~ProcessCallStack() { 122 } 123 124 void ProcessCallStack::clear() { 125 mThreadMap.clear(); 126 mTimeUpdated = tm(); 127 } 128 129 void ProcessCallStack::update() { 130 std::unique_ptr<DIR, decltype(&closedir)> dp(opendir(PATH_SELF_TASK), closedir); 131 if (dp == NULL) { 132 ALOGE("%s: Failed to update the process's call stacks: %s", 133 __FUNCTION__, strerror(errno)); 134 return; 135 } 136 137 pid_t selfPid = getpid(); 138 139 clear(); 140 141 // Get current time. 142 { 143 time_t t = time(NULL); 144 struct tm tm; 145 localtime_r(&t, &tm); 146 147 mTimeUpdated = tm; 148 } 149 150 /* 151 * Each tid is a directory inside of /proc/self/task 152 * - Read every file in directory => get every tid 153 */ 154 dirent* ep; 155 while ((ep = readdir(dp.get())) != NULL) { 156 pid_t tid = -1; 157 sscanf(ep->d_name, "%d", &tid); 158 159 if (tid < 0) { 160 // Ignore '.' and '..' 161 ALOGV("%s: Failed to read tid from %s/%s", 162 __FUNCTION__, PATH_SELF_TASK, ep->d_name); 163 continue; 164 } 165 166 ssize_t idx = mThreadMap.add(tid, ThreadInfo()); 167 if (idx < 0) { // returns negative error value on error 168 ALOGE("%s: Failed to add new ThreadInfo: %s", 169 __FUNCTION__, strerror(-idx)); 170 continue; 171 } 172 173 ThreadInfo& threadInfo = mThreadMap.editValueAt(static_cast<size_t>(idx)); 174 175 /* 176 * Ignore CallStack::update and ProcessCallStack::update for current thread 177 * - Every other thread doesn't need this since we call update off-thread 178 */ 179 int ignoreDepth = (selfPid == tid) ? IGNORE_DEPTH_CURRENT_THREAD : 0; 180 181 // Update thread's call stacks 182 threadInfo.callStack.update(ignoreDepth, tid); 183 184 // Read/save thread name 185 threadInfo.threadName = getThreadName(tid); 186 187 ALOGV("%s: Got call stack for tid %d (size %zu)", 188 __FUNCTION__, tid, threadInfo.callStack.size()); 189 } 190 } 191 192 void ProcessCallStack::log(const char* logtag, android_LogPriority priority, 193 const char* prefix) const { 194 LogPrinter printer(logtag, priority, prefix, /*ignoreBlankLines*/false); 195 print(printer); 196 } 197 198 void ProcessCallStack::print(Printer& printer) const { 199 /* 200 * Print the header/footer with the regular printer. 201 * Print the callstack with an additional two spaces as the prefix for legibility. 202 */ 203 PrefixPrinter csPrinter(printer, CALL_STACK_PREFIX); 204 printInternal(printer, csPrinter); 205 } 206 207 void ProcessCallStack::printInternal(Printer& printer, Printer& csPrinter) const { 208 dumpProcessHeader(printer, getpid(), 209 getTimeString(mTimeUpdated).string()); 210 211 for (size_t i = 0; i < mThreadMap.size(); ++i) { 212 pid_t tid = mThreadMap.keyAt(i); 213 const ThreadInfo& threadInfo = mThreadMap.valueAt(i); 214 const String8& threadName = threadInfo.threadName; 215 216 printer.printLine(""); 217 printer.printFormatLine("\"%s\" sysTid=%d", threadName.string(), tid); 218 219 threadInfo.callStack.print(csPrinter); 220 } 221 222 dumpProcessFooter(printer, getpid()); 223 } 224 225 void ProcessCallStack::dump(int fd, int indent, const char* prefix) const { 226 227 if (indent < 0) { 228 ALOGW("%s: Bad indent (%d)", __FUNCTION__, indent); 229 return; 230 } 231 232 FdPrinter printer(fd, static_cast<unsigned int>(indent), prefix); 233 print(printer); 234 } 235 236 String8 ProcessCallStack::toString(const char* prefix) const { 237 238 String8 dest; 239 String8Printer printer(&dest, prefix); 240 print(printer); 241 242 return dest; 243 } 244 245 size_t ProcessCallStack::size() const { 246 return mThreadMap.size(); 247 } 248 249 }; //namespace android 250