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