summaryrefslogtreecommitdiff
path: root/libutils/include/utils/CallStack.h
diff options
context:
space:
mode:
Diffstat (limited to 'libutils/include/utils/CallStack.h')
-rw-r--r--libutils/include/utils/CallStack.h102
1 files changed, 99 insertions, 3 deletions
diff --git a/libutils/include/utils/CallStack.h b/libutils/include/utils/CallStack.h
index 0c1b87522..56004fe49 100644
--- a/libutils/include/utils/CallStack.h
+++ b/libutils/include/utils/CallStack.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_CALLSTACK_H
#define ANDROID_CALLSTACK_H
+#include <memory>
+
#include <android/log.h>
#include <backtrace/backtrace_constants.h>
#include <utils/String8.h>
@@ -25,6 +27,19 @@
#include <stdint.h>
#include <sys/types.h>
+#if !defined(__APPLE__) && !defined(_WIN32)
+# define WEAKS_AVAILABLE 1
+#endif
+#ifndef CALLSTACK_WEAK
+# ifdef WEAKS_AVAILABLE
+# define CALLSTACK_WEAK __attribute__((weak))
+# else // !WEAKS_AVAILABLE
+# define CALLSTACK_WEAK
+# endif // !WEAKS_AVAILABLE
+#endif // CALLSTACK_WEAK predefined
+
+#define ALWAYS_INLINE __attribute__((always_inline))
+
namespace android {
class Printer;
@@ -36,7 +51,7 @@ public:
CallStack();
// Create a callstack with the current thread's stack trace.
// Immediately dump it to logcat using the given logtag.
- CallStack(const char* logtag, int32_t ignoreDepth=1);
+ CallStack(const char* logtag, int32_t ignoreDepth = 1);
~CallStack();
// Reset the stack frames (same as creating an empty call stack).
@@ -44,7 +59,7 @@ public:
// Immediately collect the stack traces for the specified thread.
// The default is to dump the stack of the current call.
- void update(int32_t ignoreDepth=1, pid_t tid=BACKTRACE_CURRENT_THREAD);
+ void update(int32_t ignoreDepth = 1, pid_t tid = BACKTRACE_CURRENT_THREAD);
// Dump a stack trace to the log using the supplied logtag.
void log(const char* logtag,
@@ -63,7 +78,88 @@ public:
// Get the count of stack frames that are in this call stack.
size_t size() const { return mFrameLines.size(); }
-private:
+ // DO NOT USE ANYTHING BELOW HERE. The following public members are expected
+ // to disappear again shortly, once a better replacement facility exists.
+ // The replacement facility will be incompatible!
+
+ // Debugging accesses to some basic functionality. These use weak symbols to
+ // avoid introducing a dependency on libutilscallstack. Such a dependency from
+ // libutils results in a cyclic build dependency. These routines can be called
+ // from within libutils. But if the actual library is unavailable, they do
+ // nothing.
+ //
+ // DO NOT USE THESE. They will disappear.
+ struct StackDeleter {
+#ifdef WEAKS_AVAILABLE
+ void operator()(CallStack* stack) {
+ deleteStack(stack);
+ }
+#else
+ void operator()(CallStack*) {}
+#endif
+ };
+
+ typedef std::unique_ptr<CallStack, StackDeleter> CallStackUPtr;
+
+ // Return current call stack if possible, nullptr otherwise.
+#ifdef WEAKS_AVAILABLE
+ static CallStackUPtr ALWAYS_INLINE getCurrent(int32_t ignoreDepth = 1) {
+ if (reinterpret_cast<uintptr_t>(getCurrentInternal) == 0) {
+ ALOGW("CallStack::getCurrentInternal not linked, returning null");
+ return CallStackUPtr(nullptr);
+ } else {
+ return getCurrentInternal(ignoreDepth);
+ }
+ }
+#else // !WEAKS_AVAILABLE
+ static CallStackUPtr ALWAYS_INLINE getCurrent(int32_t = 1) {
+ return CallStackUPtr(nullptr);
+ }
+#endif // !WEAKS_AVAILABLE
+
+#ifdef WEAKS_AVAILABLE
+ static void ALWAYS_INLINE logStack(const char* logtag, CallStack* stack = getCurrent().get(),
+ android_LogPriority priority = ANDROID_LOG_DEBUG) {
+ if (reinterpret_cast<uintptr_t>(logStackInternal) != 0 && stack != nullptr) {
+ logStackInternal(logtag, stack, priority);
+ } else {
+ ALOGW("CallStack::logStackInternal not linked");
+ }
+ }
+
+#else
+ static void ALWAYS_INLINE logStack(const char*, CallStack* = getCurrent().get(),
+ android_LogPriority = ANDROID_LOG_DEBUG) {
+ }
+#endif // !WEAKS_AVAILABLE
+
+#ifdef WEAKS_AVAILABLE
+ static String8 ALWAYS_INLINE stackToString(const char* prefix = nullptr,
+ const CallStack* stack = getCurrent().get()) {
+ if (reinterpret_cast<uintptr_t>(stackToStringInternal) != 0 && stack != nullptr) {
+ return stackToStringInternal(prefix, stack);
+ } else {
+ return String8("<CallStack package not linked>");
+ }
+ }
+#else // !WEAKS_AVAILABLE
+ static String8 ALWAYS_INLINE stackToString(const char* = nullptr,
+ const CallStack* = getCurrent().get()) {
+ return String8("<CallStack package not linked>");
+ }
+#endif // !WEAKS_AVAILABLE
+
+ private:
+#ifdef WEAKS_AVAILABLE
+ static CallStackUPtr CALLSTACK_WEAK getCurrentInternal(int32_t ignoreDepth);
+ static void CALLSTACK_WEAK logStackInternal(const char* logtag, const CallStack* stack,
+ android_LogPriority priority);
+ static String8 CALLSTACK_WEAK stackToStringInternal(const char* prefix, const CallStack* stack);
+ // The deleter is only invoked on non-null pointers. Hence it will never be
+ // invoked if CallStack is not linked.
+ static void CALLSTACK_WEAK deleteStack(CallStack* stack);
+#endif // WEAKS_AVAILABLE
+
Vector<String8> mFrameLines;
};