Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 39f18c9e authored by Igor Murashkin's avatar Igor Murashkin Committed by Android Git Automerger
Browse files

am 1b84e0a3: Merge "utils: Add ProcessCallStack to collect stack traces for...

am 1b84e0a3: Merge "utils: Add ProcessCallStack to collect stack traces for all threads in a process" into klp-dev

* commit '1b84e0a3':
  utils: Add ProcessCallStack to collect stack traces for all threads in a process
parents 9259663c 1b84e0a3
Loading
Loading
Loading
Loading
+37 −18
Original line number Diff line number Diff line
@@ -17,31 +17,41 @@
#ifndef ANDROID_CALLSTACK_H
#define ANDROID_CALLSTACK_H

#include <stdint.h>
#include <sys/types.h>

#include <android/log.h>
#include <utils/String8.h>
#include <corkscrew/backtrace.h>

// ---------------------------------------------------------------------------
#include <stdint.h>
#include <sys/types.h>

namespace android {

class CallStack
{
class Printer;

// Collect/print the call stack (function, file, line) traces for a single thread.
class CallStack {
public:
    enum {
        MAX_DEPTH = 31
        // Prune the lowest-most stack frames until we have at most MAX_DEPTH.
        MAX_DEPTH = 31,
        // Placeholder for specifying the current thread when updating the stack.
        CURRENT_THREAD = -1,
    };

    // Create an empty call stack. No-op.
    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,
            int32_t maxDepth=MAX_DEPTH);
    // Copy the existing callstack (no other side effects).
    CallStack(const CallStack& rhs);
    ~CallStack();

    // Copy the existing callstack (no other side effects).
    CallStack& operator = (const CallStack& rhs);

    // Compare call stacks by their backtrace frame memory.
    bool operator == (const CallStack& rhs) const;
    bool operator != (const CallStack& rhs) const;
    bool operator < (const CallStack& rhs) const;
@@ -49,18 +59,30 @@ public:
    bool operator > (const CallStack& rhs) const;
    bool operator <= (const CallStack& rhs) const;

    // Get the PC address for the stack frame specified by index.
    const void* operator [] (int index) const;

    // Reset the stack frames (same as creating an empty call stack).
    void clear();

    void update(int32_t ignoreDepth=1, int32_t maxDepth=MAX_DEPTH);
    // Immediately collect the stack traces for the specified thread.
    void update(int32_t ignoreDepth=1, int32_t maxDepth=MAX_DEPTH, pid_t tid=CURRENT_THREAD);

    // Dump a stack trace to the log using the supplied logtag.
    void log(const char* logtag,
             android_LogPriority priority = ANDROID_LOG_DEBUG,
             const char* prefix = 0) const;

    // Dump a stack trace to the log using the supplied logtag
    void dump(const char* logtag, const char* prefix = 0) const;
    // Dump a stack trace to the specified file descriptor.
    void dump(int fd, int indent = 0, const char* prefix = 0) const;

    // Return a string (possibly very long) containing the complete stack trace
    // Return a string (possibly very long) containing the complete stack trace.
    String8 toString(const char* prefix = 0) const;

    // Dump a serialized representation of the stack trace to the specified printer.
    void print(Printer& printer) const;

    // Get the count of stack frames that are in this call stack.
    size_t size() const { return mCount; }

private:
@@ -70,7 +92,4 @@ private:

}; // namespace android


// ---------------------------------------------------------------------------

#endif // ANDROID_CALLSTACK_H
+119 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_PRINTER_H
#define ANDROID_PRINTER_H

#include <android/log.h>

namespace android {

// Interface for printing to an arbitrary data stream
class Printer {
public:
    // Print a new line specified by 'string'. \n is appended automatically.
    // -- Assumes that the string has no new line in it.
    virtual void printLine(const char* string = "") = 0;

    // Print a new line specified by the format string. \n is appended automatically.
    // -- Assumes that the resulting string has no new line in it.
    virtual void printFormatLine(const char* format, ...) __attribute__((format (printf, 2, 3)));

protected:
    Printer();
    virtual ~Printer();
}; // class Printer

// Print to logcat
class LogPrinter : public Printer {
public:
    // Create a printer using the specified logcat and log priority
    // - Unless ignoreBlankLines is false, print blank lines to logcat
    // (Note that the default ALOG behavior is to ignore blank lines)
    LogPrinter(const char* logtag,
               android_LogPriority priority = ANDROID_LOG_DEBUG,
               const char* prefix = 0,
               bool ignoreBlankLines = false);

    // Print the specified line to logcat. No \n at the end is necessary.
    virtual void printLine(const char* string);

private:
    void printRaw(const char* string);

    const char* mLogTag;
    android_LogPriority mPriority;
    const char* mPrefix;
    bool mIgnoreBlankLines;
}; // class LogPrinter

// Print to a file descriptor
class FdPrinter : public Printer {
public:
    // Create a printer using the specified file descriptor.
    // - Each line will be prefixed with 'indent' number of blank spaces.
    // - In addition, each line will be prefixed with the 'prefix' string.
    FdPrinter(int fd, unsigned int indent = 0, const char* prefix = 0);

    // Print the specified line to the file descriptor. \n is appended automatically.
    virtual void printLine(const char* string);

private:
    enum {
        MAX_FORMAT_STRING = 20,
    };

    int mFd;
    unsigned int mIndent;
    const char* mPrefix;
    char mFormatString[MAX_FORMAT_STRING];
}; // class FdPrinter

class String8;

// Print to a String8
class String8Printer : public Printer {
public:
    // Create a printer using the specified String8 as the target.
    // - In addition, each line will be prefixed with the 'prefix' string.
    // - target's memory lifetime must be a superset of this String8Printer.
    String8Printer(String8* target, const char* prefix = 0);

    // Append the specified line to the String8. \n is appended automatically.
    virtual void printLine(const char* string);

private:
    String8* mTarget;
    const char* mPrefix;
}; // class String8Printer

// Print to an existing Printer by adding a prefix to each line
class PrefixPrinter : public Printer {
public:
    // Create a printer using the specified printer as the target.
    PrefixPrinter(Printer& printer, const char* prefix);

    // Print the line (prefixed with prefix) using the printer.
    virtual void printLine(const char* string);

private:
    Printer& mPrinter;
    const char* mPrefix;
};

}; // namespace android

#endif // ANDROID_PRINTER_H
+79 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_PROCESS_CALLSTACK_H
#define ANDROID_PROCESS_CALLSTACK_H

#include <utils/CallStack.h>
#include <android/log.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>

#include <time.h>
#include <sys/types.h>

namespace android {

class Printer;

// Collect/print the call stack (function, file, line) traces for all threads in a process.
class ProcessCallStack {
public:
    // Create an empty call stack. No-op.
    ProcessCallStack();
    // Copy the existing process callstack (no other side effects).
    ProcessCallStack(const ProcessCallStack& rhs);
    ~ProcessCallStack();

    // Immediately collect the stack traces for all threads.
    void update(int32_t maxDepth = CallStack::MAX_DEPTH);

    // Print all stack traces to the log using the supplied logtag.
    void log(const char* logtag, android_LogPriority priority = ANDROID_LOG_DEBUG,
             const char* prefix = 0) const;

    // Dump all stack traces to the specified file descriptor.
    void dump(int fd, int indent = 0, const char* prefix = 0) const;

    // Return a string (possibly very long) containing all the stack traces.
    String8 toString(const char* prefix = 0) const;

    // Dump a serialized representation of all the stack traces to the specified printer.
    void print(Printer& printer) const;

    // Get the number of threads whose stack traces were collected.
    size_t size() const;

private:
    void printInternal(Printer& printer, Printer& csPrinter) const;

    // Reset the process's stack frames and metadata.
    void clear();

    struct ThreadInfo {
        CallStack callStack;
        String8 threadName;
    };

    // tid -> ThreadInfo
    KeyedVector<pid_t, ThreadInfo> mThreadMap;
    // Time that update() was last called
    struct tm mTimeUpdated;
};

}; // namespace android

#endif // ANDROID_PROCESS_CALLSTACK_H
+2 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ commonSources:= \
	LinearAllocator.cpp \
	LinearTransform.cpp \
	Log.cpp \
	Printer.cpp \
	ProcessCallStack.cpp \
	PropertyMap.cpp \
	RefBase.cpp \
	SharedBuffer.cpp \
+33 −27
Original line number Diff line number Diff line
@@ -16,14 +16,12 @@

#define LOG_TAG "CallStack"

#include <string.h>

#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/CallStack.h>
#include <utils/Printer.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <corkscrew/backtrace.h>

/*****************************************************************************/
namespace android {

CallStack::CallStack() :
@@ -31,8 +29,8 @@ CallStack::CallStack() :
}

CallStack::CallStack(const char* logtag, int32_t ignoreDepth, int32_t maxDepth) {
    this->update(ignoreDepth+1, maxDepth);
    this->dump(logtag);
    this->update(ignoreDepth+1, maxDepth, CURRENT_THREAD);
    this->log(logtag);
}

CallStack::CallStack(const CallStack& rhs) :
@@ -93,31 +91,44 @@ void CallStack::clear() {
    mCount = 0;
}

void CallStack::update(int32_t ignoreDepth, int32_t maxDepth) {
void CallStack::update(int32_t ignoreDepth, int32_t maxDepth, pid_t tid) {
    if (maxDepth > MAX_DEPTH) {
        maxDepth = MAX_DEPTH;
    }
    ssize_t count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth);
    mCount = count > 0 ? count : 0;
    ssize_t count;

    if (tid >= 0) {
        count = unwind_backtrace_thread(tid, mStack, ignoreDepth + 1, maxDepth);
    } else if (tid == CURRENT_THREAD) {
        count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth);
    } else {
        ALOGE("%s: Invalid tid specified (%d)", __FUNCTION__, tid);
        count = 0;
    }

void CallStack::dump(const char* logtag, const char* prefix) const {
    backtrace_symbol_t symbols[mCount];
    mCount = count > 0 ? count : 0;
}

    get_backtrace_symbols(mStack, mCount, symbols);
    for (size_t i = 0; i < mCount; i++) {
        char line[MAX_BACKTRACE_LINE_LENGTH];
        format_backtrace_line(i, &mStack[i], &symbols[i],
                line, MAX_BACKTRACE_LINE_LENGTH);
        ALOG(LOG_DEBUG, logtag, "%s%s",
                prefix ? prefix : "",
                line);
void CallStack::log(const char* logtag, android_LogPriority priority, const char* prefix) const {
    LogPrinter printer(logtag, priority, prefix, /*ignoreBlankLines*/false);
    print(printer);
}
    free_backtrace_symbols(symbols, mCount);

void CallStack::dump(int fd, int indent, const char* prefix) const {
    FdPrinter printer(fd, indent, prefix);
    print(printer);
}

String8 CallStack::toString(const char* prefix) const {
    String8 str;

    String8Printer printer(&str, prefix);
    print(printer);

    return str;
}

void CallStack::print(Printer& printer) const {
    backtrace_symbol_t symbols[mCount];

    get_backtrace_symbols(mStack, mCount, symbols);
@@ -125,14 +136,9 @@ String8 CallStack::toString(const char* prefix) const {
        char line[MAX_BACKTRACE_LINE_LENGTH];
        format_backtrace_line(i, &mStack[i], &symbols[i],
                line, MAX_BACKTRACE_LINE_LENGTH);
        if (prefix) {
            str.append(prefix);
        }
        str.append(line);
        str.append("\n");
        printer.printLine(line);
    }
    free_backtrace_symbols(symbols, mCount);
    return str;
}

}; // namespace android
Loading