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