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 
dumpProcessHeader(Printer & printer,pid_t pid,const char * timeStr)44 static void dumpProcessHeader(Printer& printer, pid_t pid, const char* timeStr) {
45     if (timeStr == nullptr) {
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 = nullptr;
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 
dumpProcessFooter(Printer & printer,pid_t pid)71 static void dumpProcessFooter(Printer& printer, pid_t pid) {
72     printer.printLine();
73     printer.printFormatLine("----- end %d -----", pid);
74     printer.printLine();
75 }
76 
getThreadName(pid_t tid)77 static String8 getThreadName(pid_t tid) {
78     char path[PATH_MAX];
79     char* procName = nullptr;
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 == nullptr) {
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 
getTimeString(struct tm tm)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  */
ProcessCallStack()113 ProcessCallStack::ProcessCallStack() {
114 }
115 
ProcessCallStack(const ProcessCallStack & rhs)116 ProcessCallStack::ProcessCallStack(const ProcessCallStack& rhs) :
117         mThreadMap(rhs.mThreadMap),
118         mTimeUpdated(rhs.mTimeUpdated) {
119 }
120 
~ProcessCallStack()121 ProcessCallStack::~ProcessCallStack() {
122 }
123 
clear()124 void ProcessCallStack::clear() {
125     mThreadMap.clear();
126     mTimeUpdated = tm();
127 }
128 
update()129 void ProcessCallStack::update() {
130     std::unique_ptr<DIR, decltype(&closedir)> dp(opendir(PATH_SELF_TASK), closedir);
131     if (dp == nullptr) {
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(nullptr);
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())) != nullptr) {
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 
log(const char * logtag,android_LogPriority priority,const char * prefix) const192 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 
print(Printer & printer) const198 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 
printInternal(Printer & printer,Printer & csPrinter) const207 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 
dump(int fd,int indent,const char * prefix) const225 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 
toString(const char * prefix) const236 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 
size() const245 size_t ProcessCallStack::size() const {
246     return mThreadMap.size();
247 }
248 
249 }; //namespace android
250