summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor Murashkin2013-10-24 19:09:15 -0500
committerIgor Murashkin2013-10-25 21:24:56 -0500
commitec79ef2e7b6b1d81266637ca0e002b5c0c5a789b (patch)
tree309ff8a328db5ccd522995abe3614959cfded1c6
parenta9e453f1b552699f69dca19599c7624a581089bd (diff)
downloadplatform-system-core-ec79ef2e7b6b1d81266637ca0e002b5c0c5a789b.tar.gz
platform-system-core-ec79ef2e7b6b1d81266637ca0e002b5c0c5a789b.tar.xz
platform-system-core-ec79ef2e7b6b1d81266637ca0e002b5c0c5a789b.zip
utils: Add ProcessCallStack to collect stack traces for all threads in a process
- Also add a Printer class (print lines to logcat, fd, or strings) Bug: 11324229 Change-Id: I78435ed49aa196a0efb45bf9b2d58b62c41737d3
-rw-r--r--include/utils/CallStack.h55
-rw-r--r--include/utils/Printer.h119
-rw-r--r--include/utils/ProcessCallStack.h79
-rw-r--r--libutils/Android.mk2
-rw-r--r--libutils/CallStack.cpp60
-rw-r--r--libutils/Printer.cpp155
-rw-r--r--libutils/ProcessCallStack.cpp256
7 files changed, 681 insertions, 45 deletions
diff --git a/include/utils/CallStack.h b/include/utils/CallStack.h
index 61dc832ea..205675173 100644
--- a/include/utils/CallStack.h
+++ b/include/utils/CallStack.h
@@ -17,50 +17,72 @@
17#ifndef ANDROID_CALLSTACK_H 17#ifndef ANDROID_CALLSTACK_H
18#define ANDROID_CALLSTACK_H 18#define ANDROID_CALLSTACK_H
19 19
20#include <stdint.h> 20#include <android/log.h>
21#include <sys/types.h>
22
23#include <utils/String8.h> 21#include <utils/String8.h>
24#include <corkscrew/backtrace.h> 22#include <corkscrew/backtrace.h>
25 23
26// --------------------------------------------------------------------------- 24#include <stdint.h>
25#include <sys/types.h>
27 26
28namespace android { 27namespace android {
29 28
30class CallStack 29class Printer;
31{ 30
31// Collect/print the call stack (function, file, line) traces for a single thread.
32class CallStack {
32public: 33public:
33 enum { 34 enum {
34 MAX_DEPTH = 31 35 // Prune the lowest-most stack frames until we have at most MAX_DEPTH.
36 MAX_DEPTH = 31,
37 // Placeholder for specifying the current thread when updating the stack.
38 CURRENT_THREAD = -1,
35 }; 39 };
36 40
41 // Create an empty call stack. No-op.
37 CallStack(); 42 CallStack();
43 // Create a callstack with the current thread's stack trace.
44 // Immediately dump it to logcat using the given logtag.
38 CallStack(const char* logtag, int32_t ignoreDepth=1, 45 CallStack(const char* logtag, int32_t ignoreDepth=1,
39 int32_t maxDepth=MAX_DEPTH); 46 int32_t maxDepth=MAX_DEPTH);
47 // Copy the existing callstack (no other side effects).
40 CallStack(const CallStack& rhs); 48 CallStack(const CallStack& rhs);
41 ~CallStack(); 49 ~CallStack();
42 50
51 // Copy the existing callstack (no other side effects).
43 CallStack& operator = (const CallStack& rhs); 52 CallStack& operator = (const CallStack& rhs);
44 53
54 // Compare call stacks by their backtrace frame memory.
45 bool operator == (const CallStack& rhs) const; 55 bool operator == (const CallStack& rhs) const;
46 bool operator != (const CallStack& rhs) const; 56 bool operator != (const CallStack& rhs) const;
47 bool operator < (const CallStack& rhs) const; 57 bool operator < (const CallStack& rhs) const;
48 bool operator >= (const CallStack& rhs) const; 58 bool operator >= (const CallStack& rhs) const;
49 bool operator > (const CallStack& rhs) const; 59 bool operator > (const CallStack& rhs) const;
50 bool operator <= (const CallStack& rhs) const; 60 bool operator <= (const CallStack& rhs) const;
51 61
62 // Get the PC address for the stack frame specified by index.
52 const void* operator [] (int index) const; 63 const void* operator [] (int index) const;
53 64
65 // Reset the stack frames (same as creating an empty call stack).
54 void clear(); 66 void clear();
55 67
56 void update(int32_t ignoreDepth=1, int32_t maxDepth=MAX_DEPTH); 68 // Immediately collect the stack traces for the specified thread.
69 void update(int32_t ignoreDepth=1, int32_t maxDepth=MAX_DEPTH, pid_t tid=CURRENT_THREAD);
57 70
58 // Dump a stack trace to the log using the supplied logtag 71 // Dump a stack trace to the log using the supplied logtag.
59 void dump(const char* logtag, const char* prefix = 0) const; 72 void log(const char* logtag,
73 android_LogPriority priority = ANDROID_LOG_DEBUG,
74 const char* prefix = 0) const;
60 75
61 // Return a string (possibly very long) containing the complete stack trace 76 // Dump a stack trace to the specified file descriptor.
77 void dump(int fd, int indent = 0, const char* prefix = 0) const;
78
79 // Return a string (possibly very long) containing the complete stack trace.
62 String8 toString(const char* prefix = 0) const; 80 String8 toString(const char* prefix = 0) const;
63 81
82 // Dump a serialized representation of the stack trace to the specified printer.
83 void print(Printer& printer) const;
84
85 // Get the count of stack frames that are in this call stack.
64 size_t size() const { return mCount; } 86 size_t size() const { return mCount; }
65 87
66private: 88private:
@@ -70,7 +92,4 @@ private:
70 92
71}; // namespace android 93}; // namespace android
72 94
73
74// ---------------------------------------------------------------------------
75
76#endif // ANDROID_CALLSTACK_H 95#endif // ANDROID_CALLSTACK_H
diff --git a/include/utils/Printer.h b/include/utils/Printer.h
new file mode 100644
index 000000000..bb6628767
--- /dev/null
+++ b/include/utils/Printer.h
@@ -0,0 +1,119 @@
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#ifndef ANDROID_PRINTER_H
18#define ANDROID_PRINTER_H
19
20#include <android/log.h>
21
22namespace android {
23
24// Interface for printing to an arbitrary data stream
25class Printer {
26public:
27 // Print a new line specified by 'string'. \n is appended automatically.
28 // -- Assumes that the string has no new line in it.
29 virtual void printLine(const char* string = "") = 0;
30
31 // Print a new line specified by the format string. \n is appended automatically.
32 // -- Assumes that the resulting string has no new line in it.
33 virtual void printFormatLine(const char* format, ...) __attribute__((format (printf, 2, 3)));
34
35protected:
36 Printer();
37 virtual ~Printer();
38}; // class Printer
39
40// Print to logcat
41class LogPrinter : public Printer {
42public:
43 // Create a printer using the specified logcat and log priority
44 // - Unless ignoreBlankLines is false, print blank lines to logcat
45 // (Note that the default ALOG behavior is to ignore blank lines)
46 LogPrinter(const char* logtag,
47 android_LogPriority priority = ANDROID_LOG_DEBUG,
48 const char* prefix = 0,
49 bool ignoreBlankLines = false);
50
51 // Print the specified line to logcat. No \n at the end is necessary.
52 virtual void printLine(const char* string);
53
54private:
55 void printRaw(const char* string);
56
57 const char* mLogTag;
58 android_LogPriority mPriority;
59 const char* mPrefix;
60 bool mIgnoreBlankLines;
61}; // class LogPrinter
62
63// Print to a file descriptor
64class FdPrinter : public Printer {
65public:
66 // Create a printer using the specified file descriptor.
67 // - Each line will be prefixed with 'indent' number of blank spaces.
68 // - In addition, each line will be prefixed with the 'prefix' string.
69 FdPrinter(int fd, unsigned int indent = 0, const char* prefix = 0);
70
71 // Print the specified line to the file descriptor. \n is appended automatically.
72 virtual void printLine(const char* string);
73
74private:
75 enum {
76 MAX_FORMAT_STRING = 20,
77 };
78
79 int mFd;
80 unsigned int mIndent;
81 const char* mPrefix;
82 char mFormatString[MAX_FORMAT_STRING];
83}; // class FdPrinter
84
85class String8;
86
87// Print to a String8
88class String8Printer : public Printer {
89public:
90 // Create a printer using the specified String8 as the target.
91 // - In addition, each line will be prefixed with the 'prefix' string.
92 // - target's memory lifetime must be a superset of this String8Printer.
93 String8Printer(String8* target, const char* prefix = 0);
94
95 // Append the specified line to the String8. \n is appended automatically.
96 virtual void printLine(const char* string);
97
98private:
99 String8* mTarget;
100 const char* mPrefix;
101}; // class String8Printer
102
103// Print to an existing Printer by adding a prefix to each line
104class PrefixPrinter : public Printer {
105public:
106 // Create a printer using the specified printer as the target.
107 PrefixPrinter(Printer& printer, const char* prefix);
108
109 // Print the line (prefixed with prefix) using the printer.
110 virtual void printLine(const char* string);
111
112private:
113 Printer& mPrinter;
114 const char* mPrefix;
115};
116
117}; // namespace android
118
119#endif // ANDROID_PRINTER_H
diff --git a/include/utils/ProcessCallStack.h b/include/utils/ProcessCallStack.h
new file mode 100644
index 000000000..4a8686958
--- /dev/null
+++ b/include/utils/ProcessCallStack.h
@@ -0,0 +1,79 @@
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#ifndef ANDROID_PROCESS_CALLSTACK_H
18#define ANDROID_PROCESS_CALLSTACK_H
19
20#include <utils/CallStack.h>
21#include <android/log.h>
22#include <utils/KeyedVector.h>
23#include <utils/String8.h>
24
25#include <time.h>
26#include <sys/types.h>
27
28namespace android {
29
30class Printer;
31
32// Collect/print the call stack (function, file, line) traces for all threads in a process.
33class ProcessCallStack {
34public:
35 // Create an empty call stack. No-op.
36 ProcessCallStack();
37 // Copy the existing process callstack (no other side effects).
38 ProcessCallStack(const ProcessCallStack& rhs);
39 ~ProcessCallStack();
40
41 // Immediately collect the stack traces for all threads.
42 void update(int32_t maxDepth = CallStack::MAX_DEPTH);
43
44 // Print all stack traces to the log using the supplied logtag.
45 void log(const char* logtag, android_LogPriority priority = ANDROID_LOG_DEBUG,
46 const char* prefix = 0) const;
47
48 // Dump all stack traces to the specified file descriptor.
49 void dump(int fd, int indent = 0, const char* prefix = 0) const;
50
51 // Return a string (possibly very long) containing all the stack traces.
52 String8 toString(const char* prefix = 0) const;
53
54 // Dump a serialized representation of all the stack traces to the specified printer.
55 void print(Printer& printer) const;
56
57 // Get the number of threads whose stack traces were collected.
58 size_t size() const;
59
60private:
61 void printInternal(Printer& printer, Printer& csPrinter) const;
62
63 // Reset the process's stack frames and metadata.
64 void clear();
65
66 struct ThreadInfo {
67 CallStack callStack;
68 String8 threadName;
69 };
70
71 // tid -> ThreadInfo
72 KeyedVector<pid_t, ThreadInfo> mThreadMap;
73 // Time that update() was last called
74 struct tm mTimeUpdated;
75};
76
77}; // namespace android
78
79#endif // ANDROID_PROCESS_CALLSTACK_H
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 7e6b1be42..720443e88 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -26,6 +26,8 @@ commonSources:= \
26 LinearAllocator.cpp \ 26 LinearAllocator.cpp \
27 LinearTransform.cpp \ 27 LinearTransform.cpp \
28 Log.cpp \ 28 Log.cpp \
29 Printer.cpp \
30 ProcessCallStack.cpp \
29 PropertyMap.cpp \ 31 PropertyMap.cpp \
30 RefBase.cpp \ 32 RefBase.cpp \
31 SharedBuffer.cpp \ 33 SharedBuffer.cpp \
diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp
index e60f5d8e7..4ceaa7c91 100644
--- a/libutils/CallStack.cpp
+++ b/libutils/CallStack.cpp
@@ -16,14 +16,12 @@
16 16
17#define LOG_TAG "CallStack" 17#define LOG_TAG "CallStack"
18 18
19#include <string.h>
20
21#include <utils/Log.h>
22#include <utils/Errors.h>
23#include <utils/CallStack.h> 19#include <utils/CallStack.h>
20#include <utils/Printer.h>
21#include <utils/Errors.h>
22#include <utils/Log.h>
24#include <corkscrew/backtrace.h> 23#include <corkscrew/backtrace.h>
25 24
26/*****************************************************************************/
27namespace android { 25namespace android {
28 26
29CallStack::CallStack() : 27CallStack::CallStack() :
@@ -31,8 +29,8 @@ CallStack::CallStack() :
31} 29}
32 30
33CallStack::CallStack(const char* logtag, int32_t ignoreDepth, int32_t maxDepth) { 31CallStack::CallStack(const char* logtag, int32_t ignoreDepth, int32_t maxDepth) {
34 this->update(ignoreDepth+1, maxDepth); 32 this->update(ignoreDepth+1, maxDepth, CURRENT_THREAD);
35 this->dump(logtag); 33 this->log(logtag);
36} 34}
37 35
38CallStack::CallStack(const CallStack& rhs) : 36CallStack::CallStack(const CallStack& rhs) :
@@ -93,31 +91,44 @@ void CallStack::clear() {
93 mCount = 0; 91 mCount = 0;
94} 92}
95 93
96void CallStack::update(int32_t ignoreDepth, int32_t maxDepth) { 94void CallStack::update(int32_t ignoreDepth, int32_t maxDepth, pid_t tid) {
97 if (maxDepth > MAX_DEPTH) { 95 if (maxDepth > MAX_DEPTH) {
98 maxDepth = MAX_DEPTH; 96 maxDepth = MAX_DEPTH;
99 } 97 }
100 ssize_t count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth); 98 ssize_t count;
99
100 if (tid >= 0) {
101 count = unwind_backtrace_thread(tid, mStack, ignoreDepth + 1, maxDepth);
102 } else if (tid == CURRENT_THREAD) {
103 count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth);
104 } else {
105 ALOGE("%s: Invalid tid specified (%d)", __FUNCTION__, tid);
106 count = 0;
107 }
108
101 mCount = count > 0 ? count : 0; 109 mCount = count > 0 ? count : 0;
102} 110}
103 111
104void CallStack::dump(const char* logtag, const char* prefix) const { 112void CallStack::log(const char* logtag, android_LogPriority priority, const char* prefix) const {
105 backtrace_symbol_t symbols[mCount]; 113 LogPrinter printer(logtag, priority, prefix, /*ignoreBlankLines*/false);
114 print(printer);
115}
106 116
107 get_backtrace_symbols(mStack, mCount, symbols); 117void CallStack::dump(int fd, int indent, const char* prefix) const {
108 for (size_t i = 0; i < mCount; i++) { 118 FdPrinter printer(fd, indent, prefix);
109 char line[MAX_BACKTRACE_LINE_LENGTH]; 119 print(printer);
110 format_backtrace_line(i, &mStack[i], &symbols[i],
111 line, MAX_BACKTRACE_LINE_LENGTH);
112 ALOG(LOG_DEBUG, logtag, "%s%s",
113 prefix ? prefix : "",
114 line);
115 }
116 free_backtrace_symbols(symbols, mCount);
117} 120}
118 121
119String8 CallStack::toString(const char* prefix) const { 122String8 CallStack::toString(const char* prefix) const {
120 String8 str; 123 String8 str;
124
125 String8Printer printer(&str, prefix);
126 print(printer);
127
128 return str;
129}
130
131void CallStack::print(Printer& printer) const {
121 backtrace_symbol_t symbols[mCount]; 132 backtrace_symbol_t symbols[mCount];
122 133
123 get_backtrace_symbols(mStack, mCount, symbols); 134 get_backtrace_symbols(mStack, mCount, symbols);
@@ -125,14 +136,9 @@ String8 CallStack::toString(const char* prefix) const {
125 char line[MAX_BACKTRACE_LINE_LENGTH]; 136 char line[MAX_BACKTRACE_LINE_LENGTH];
126 format_backtrace_line(i, &mStack[i], &symbols[i], 137 format_backtrace_line(i, &mStack[i], &symbols[i],
127 line, MAX_BACKTRACE_LINE_LENGTH); 138 line, MAX_BACKTRACE_LINE_LENGTH);
128 if (prefix) { 139 printer.printLine(line);
129 str.append(prefix);
130 }
131 str.append(line);
132 str.append("\n");
133 } 140 }
134 free_backtrace_symbols(symbols, mCount); 141 free_backtrace_symbols(symbols, mCount);
135 return str;
136} 142}
137 143
138}; // namespace android 144}; // namespace android
diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp
new file mode 100644
index 000000000..b062ef0a7
--- /dev/null
+++ b/libutils/Printer.cpp
@@ -0,0 +1,155 @@
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 "Printer"
18// #define LOG_NDEBUG 0
19
20#include <utils/Printer.h>
21#include <utils/String8.h>
22#include <utils/Log.h>
23
24#include <string.h>
25#include <stdio.h>
26#include <stdlib.h>
27
28#ifndef __BIONIC__
29#define fdprintf dprintf
30#endif
31
32namespace android {
33
34/*
35 * Implementation of Printer
36 */
37Printer::Printer() {
38 // Intentionally left empty
39}
40
41Printer::~Printer() {
42 // Intentionally left empty
43}
44
45void Printer::printFormatLine(const char* format, ...) {
46 va_list arglist;
47 va_start(arglist, format);
48
49 char* formattedString;
50 if (vasprintf(&formattedString, format, arglist) < 0) { // returns -1 on error
51 ALOGE("%s: Failed to format string", __FUNCTION__);
52 return;
53 }
54 va_end(arglist);
55
56 printLine(formattedString);
57 free(formattedString);
58}
59
60/*
61 * Implementation of LogPrinter
62 */
63LogPrinter::LogPrinter(const char* logtag,
64 android_LogPriority priority,
65 const char* prefix,
66 bool ignoreBlankLines) :
67 mLogTag(logtag),
68 mPriority(priority),
69 mPrefix(prefix ?: ""),
70 mIgnoreBlankLines(ignoreBlankLines) {
71}
72
73void LogPrinter::printLine(const char* string) {
74 if (string == NULL) {
75 ALOGW("%s: NULL string passed in", __FUNCTION__);
76 return;
77 }
78
79 if (mIgnoreBlankLines || (*string)) {
80 // Simple case: Line is not blank, or we don't care about printing blank lines
81 printRaw(string);
82 } else {
83 // Force logcat to print empty lines by adding prefixing with a space
84 printRaw(" ");
85 }
86}
87
88void LogPrinter::printRaw(const char* string) {
89 __android_log_print(mPriority, mLogTag, "%s%s", mPrefix, string);
90}
91
92
93/*
94 * Implementation of FdPrinter
95 */
96FdPrinter::FdPrinter(int fd, unsigned int indent, const char* prefix) :
97 mFd(fd), mIndent(indent), mPrefix(prefix ?: "") {
98
99 if (fd < 0) {
100 ALOGW("%s: File descriptor out of range (%d)", __FUNCTION__, fd);
101 }
102
103 // <indent><prefix><line> -- e.g. '%-4s%s\n' for indent=4
104 snprintf(mFormatString, sizeof(mFormatString), "%%-%us%%s\n", mIndent);
105}
106
107void FdPrinter::printLine(const char* string) {
108 if (string == NULL) {
109 ALOGW("%s: NULL string passed in", __FUNCTION__);
110 return;
111 } else if (mFd < 0) {
112 ALOGW("%s: File descriptor out of range (%d)", __FUNCTION__, mFd);
113 return;
114 }
115
116 fdprintf(mFd, mFormatString, mPrefix, string);
117}
118
119/*
120 * Implementation of String8Printer
121 */
122String8Printer::String8Printer(String8* target, const char* prefix) :
123 mTarget(target),
124 mPrefix(prefix ?: "") {
125
126 if (target == NULL) {
127 ALOGW("%s: Target string was NULL", __FUNCTION__);
128 }
129}
130
131void String8Printer::printLine(const char* string) {
132 if (string == NULL) {
133 ALOGW("%s: NULL string passed in", __FUNCTION__);
134 return;
135 } else if (mTarget == NULL) {
136 ALOGW("%s: Target string was NULL", __FUNCTION__);
137 return;
138 }
139
140 mTarget->append(string);
141 mTarget->append("\n");
142}
143
144/*
145 * Implementation of PrefixPrinter
146 */
147PrefixPrinter::PrefixPrinter(Printer& printer, const char* prefix) :
148 mPrinter(printer), mPrefix(prefix ?: "") {
149}
150
151void PrefixPrinter::printLine(const char* string) {
152 mPrinter.printFormatLine("%s%s", mPrefix, string);
153}
154
155}; //namespace android
diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp
new file mode 100644
index 000000000..ed35237a0
--- /dev/null
+++ b/libutils/ProcessCallStack.cpp
@@ -0,0 +1,256 @@
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 <string.h>
21#include <stdio.h>
22#include <dirent.h>
23
24#include <utils/Log.h>
25#include <utils/Errors.h>
26#include <utils/ProcessCallStack.h>
27#include <utils/Printer.h>
28
29namespace android {
30
31enum {
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
40static const char* CALL_STACK_PREFIX = " ";
41static const char* PATH_THREAD_NAME = "/proc/self/task/%d/comm";
42static const char* PATH_SELF_TASK = "/proc/self/task";
43
44static 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
71static void dumpProcessFooter(Printer& printer, pid_t pid) {
72 printer.printLine();
73 printer.printFormatLine("----- end %d -----", pid);
74 printer.printLine();
75}
76
77static 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 // Strip ending newline
92 strtok(procName, "\n");
93
94 return String8(procName);
95}
96
97static String8 getTimeString(struct tm tm) {
98 char timestr[MAX_TIME_STRING];
99 // i.e. '2013-10-22 14:42:05'
100 strftime(timestr, sizeof(timestr), "%F %T", &tm);
101
102 return String8(timestr);
103}
104
105/*
106 * Implementation of ProcessCallStack
107 */
108ProcessCallStack::ProcessCallStack() {
109}
110
111ProcessCallStack::ProcessCallStack(const ProcessCallStack& rhs) :
112 mThreadMap(rhs.mThreadMap),
113 mTimeUpdated(rhs.mTimeUpdated) {
114}
115
116ProcessCallStack::~ProcessCallStack() {
117}
118
119void ProcessCallStack::clear() {
120 mThreadMap.clear();
121 mTimeUpdated = tm();
122}
123
124void ProcessCallStack::update(int32_t maxDepth) {
125 DIR *dp;
126 struct dirent *ep;
127 struct dirent entry;
128
129 dp = opendir(PATH_SELF_TASK);
130 if (dp == NULL) {
131 ALOGE("%s: Failed to update the process's call stacks (errno = %d, '%s')",
132 __FUNCTION__, errno, strerror(errno));
133 return;
134 }
135
136 pid_t selfPid = getpid();
137
138 clear();
139
140 // Get current time.
141 {
142 time_t t = time(NULL);
143 struct tm tm;
144 localtime_r(&t, &tm);
145
146 mTimeUpdated = tm;
147 }
148
149 /*
150 * Each tid is a directory inside of /proc/self/task
151 * - Read every file in directory => get every tid
152 */
153 int code;
154 while ((code = readdir_r(dp, &entry, &ep)) == 0 && ep != NULL) {
155 pid_t tid = -1;
156 sscanf(ep->d_name, "%d", &tid);
157
158 if (tid < 0) {
159 // Ignore '.' and '..'
160 ALOGV("%s: Failed to read tid from %s/%s",
161 __FUNCTION__, PATH_SELF_TASK, ep->d_name);
162 continue;
163 }
164
165 ssize_t idx = mThreadMap.add(tid, ThreadInfo());
166 if (idx < 0) { // returns negative error value on error
167 ALOGE("%s: Failed to add new ThreadInfo (errno = %zd, '%s')",
168 __FUNCTION__, idx, strerror(-idx));
169 continue;
170 }
171
172 ThreadInfo& threadInfo = mThreadMap.editValueAt(static_cast<size_t>(idx));
173
174 /*
175 * Ignore CallStack::update and ProcessCallStack::update for current thread
176 * - Every other thread doesn't need this since we call update off-thread
177 */
178 int ignoreDepth = (selfPid == tid) ? IGNORE_DEPTH_CURRENT_THREAD : 0;
179
180 // Update thread's call stacks
181 CallStack& cs = threadInfo.callStack;
182 cs.update(ignoreDepth, maxDepth, 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, cs.size());
189 }
190 if (code != 0) { // returns positive error value on error
191 ALOGE("%s: Failed to readdir from %s (errno = %d, '%s')",
192 __FUNCTION__, PATH_SELF_TASK, -code, strerror(code));
193 }
194
195 closedir(dp);
196}
197
198void ProcessCallStack::log(const char* logtag, android_LogPriority priority,
199 const char* prefix) const {
200 LogPrinter printer(logtag, priority, prefix, /*ignoreBlankLines*/false);
201 print(printer);
202}
203
204void ProcessCallStack::print(Printer& printer) const {
205 /*
206 * Print the header/footer with the regular printer.
207 * Print the callstack with an additional two spaces as the prefix for legibility.
208 */
209 PrefixPrinter csPrinter(printer, CALL_STACK_PREFIX);
210 printInternal(printer, csPrinter);
211}
212
213void ProcessCallStack::printInternal(Printer& printer, Printer& csPrinter) const {
214 dumpProcessHeader(printer, getpid(),
215 getTimeString(mTimeUpdated).string());
216
217 for (size_t i = 0; i < mThreadMap.size(); ++i) {
218 pid_t tid = mThreadMap.keyAt(i);
219 const ThreadInfo& threadInfo = mThreadMap.valueAt(i);
220 const CallStack& cs = threadInfo.callStack;
221 const String8& threadName = threadInfo.threadName;
222
223 printer.printLine("");
224 printer.printFormatLine("\"%s\" sysTid=%d", threadName.string(), tid);
225
226 cs.print(csPrinter);
227 }
228
229 dumpProcessFooter(printer, getpid());
230}
231
232void ProcessCallStack::dump(int fd, int indent, const char* prefix) const {
233
234 if (indent < 0) {
235 ALOGW("%s: Bad indent (%d)", __FUNCTION__, indent);
236 return;
237 }
238
239 FdPrinter printer(fd, static_cast<unsigned int>(indent), prefix);
240 print(printer);
241}
242
243String8 ProcessCallStack::toString(const char* prefix) const {
244
245 String8 dest;
246 String8Printer printer(&dest, prefix);
247 print(printer);
248
249 return dest;
250}
251
252size_t ProcessCallStack::size() const {
253 return mThreadMap.size();
254}
255
256}; //namespace android