From 00c8e1a2199b2f9c50935bb4ea8bb3b86ba1bbef Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 17 Oct 2013 16:25:14 -0700 Subject: [PATCH 1/6] vold no longer does MS_MOVE; remove tmpfs. MS_MOVE was used when staging external storage devices, which no longer occurs. In fact, having a writable tmpfs was masking a vold bug around moving apps to SD cards. Bug: 11175082 Change-Id: Ib2d7561c3a0b6fde94f651a496cb0c1f12f88d96 --- rootdir/init.rc | 3 --- 1 file changed, 3 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 86e124f15..a0a98134b 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -66,8 +66,6 @@ loglevel 3 # Directory for putting things only root should see. mkdir /mnt/secure 0700 root root - # Create private mountpoint so we can MS_MOVE from staging - mount tmpfs tmpfs /mnt/secure mode=0700,uid=0,gid=0 # Directory for staging bindmounts mkdir /mnt/secure/staging 0700 root root @@ -143,7 +141,6 @@ on post-fs mount rootfs rootfs / ro remount # mount shared so changes propagate into child namespaces mount rootfs rootfs / shared rec - mount tmpfs tmpfs /mnt/secure private rec # We chown/chmod /cache again so because mount is run as root + defaults chown system cache /cache From 917045222a69021eb36aea96708649c709685509 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Thu, 24 Oct 2013 08:53:48 -0700 Subject: [PATCH 2/6] Don't return immediately from reboot commands. The reboot commands return too fast, interfering with testing. Add a pause(), which will allow the device time to complete the reboot. Change-Id: Ie9cc6eea67b7ff662ec71ea2329cbb94f8d55404 Bug: 11369303 --- adb/services.c | 4 ++++ reboot/reboot.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/adb/services.c b/adb/services.c index f0d587817..951048e58 100644 --- a/adb/services.c +++ b/adb/services.c @@ -144,7 +144,11 @@ void reboot_service(int fd, void *arg) if (ret < 0) { snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret); writex(fd, buf, strlen(buf)); + goto cleanup; } + // Don't return early. Give the reboot command time to take effect + // to avoid messing up scripts which do "adb reboot && adb wait-for-device" + while(1) { pause(); } cleanup: free(arg); adb_close(fd); diff --git a/reboot/reboot.c b/reboot/reboot.c index 0e5170d42..d9a422764 100644 --- a/reboot/reboot.c +++ b/reboot/reboot.c @@ -68,6 +68,11 @@ int main(int argc, char *argv[]) perror("reboot"); exit(EXIT_FAILURE); } + + // Don't return early. Give the reboot command time to take effect + // to avoid messing up scripts which do "adb shell reboot && adb wait-for-device" + while(1) { pause(); } + fprintf(stderr, "Done\n"); return 0; } From ec79ef2e7b6b1d81266637ca0e002b5c0c5a789b Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Thu, 24 Oct 2013 17:09:15 -0700 Subject: [PATCH 3/6] 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 --- include/utils/CallStack.h | 55 ++++--- include/utils/Printer.h | 119 ++++++++++++++ include/utils/ProcessCallStack.h | 79 ++++++++++ libutils/Android.mk | 2 + libutils/CallStack.cpp | 60 ++++---- libutils/Printer.cpp | 155 +++++++++++++++++++ libutils/ProcessCallStack.cpp | 256 +++++++++++++++++++++++++++++++ 7 files changed, 681 insertions(+), 45 deletions(-) create mode 100644 include/utils/Printer.h create mode 100644 include/utils/ProcessCallStack.h create mode 100644 libutils/Printer.cpp create mode 100644 libutils/ProcessCallStack.cpp 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 @@ #ifndef ANDROID_CALLSTACK_H #define ANDROID_CALLSTACK_H -#include -#include - +#include #include #include -// --------------------------------------------------------------------------- +#include +#include 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; bool operator >= (const CallStack& rhs) const; 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 dump(const char* logtag, const char* prefix = 0) const; + // 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; - // Return a string (possibly very long) containing the complete stack trace + // 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. 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 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 @@ +/* + * 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 + +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 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 @@ +/* + * 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 +#include +#include +#include + +#include +#include + +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 mThreadMap; + // Time that update() was last called + struct tm mTimeUpdated; +}; + +}; // namespace android + +#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:= \ LinearAllocator.cpp \ LinearTransform.cpp \ Log.cpp \ + Printer.cpp \ + ProcessCallStack.cpp \ PropertyMap.cpp \ RefBase.cpp \ 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 @@ #define LOG_TAG "CallStack" -#include - -#include -#include #include +#include +#include +#include #include -/*****************************************************************************/ 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); + 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; + } + mCount = count > 0 ? count : 0; } -void CallStack::dump(const char* logtag, const char* prefix) const { - backtrace_symbol_t symbols[mCount]; +void CallStack::log(const char* logtag, android_LogPriority priority, const char* prefix) const { + LogPrinter printer(logtag, priority, prefix, /*ignoreBlankLines*/false); + print(printer); +} - 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); - } - 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 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 @@ +/* + * 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. + */ + +#define LOG_TAG "Printer" +// #define LOG_NDEBUG 0 + +#include +#include +#include + +#include +#include +#include + +#ifndef __BIONIC__ +#define fdprintf dprintf +#endif + +namespace android { + +/* + * Implementation of Printer + */ +Printer::Printer() { + // Intentionally left empty +} + +Printer::~Printer() { + // Intentionally left empty +} + +void Printer::printFormatLine(const char* format, ...) { + va_list arglist; + va_start(arglist, format); + + char* formattedString; + if (vasprintf(&formattedString, format, arglist) < 0) { // returns -1 on error + ALOGE("%s: Failed to format string", __FUNCTION__); + return; + } + va_end(arglist); + + printLine(formattedString); + free(formattedString); +} + +/* + * Implementation of LogPrinter + */ +LogPrinter::LogPrinter(const char* logtag, + android_LogPriority priority, + const char* prefix, + bool ignoreBlankLines) : + mLogTag(logtag), + mPriority(priority), + mPrefix(prefix ?: ""), + mIgnoreBlankLines(ignoreBlankLines) { +} + +void LogPrinter::printLine(const char* string) { + if (string == NULL) { + ALOGW("%s: NULL string passed in", __FUNCTION__); + return; + } + + if (mIgnoreBlankLines || (*string)) { + // Simple case: Line is not blank, or we don't care about printing blank lines + printRaw(string); + } else { + // Force logcat to print empty lines by adding prefixing with a space + printRaw(" "); + } +} + +void LogPrinter::printRaw(const char* string) { + __android_log_print(mPriority, mLogTag, "%s%s", mPrefix, string); +} + + +/* + * Implementation of FdPrinter + */ +FdPrinter::FdPrinter(int fd, unsigned int indent, const char* prefix) : + mFd(fd), mIndent(indent), mPrefix(prefix ?: "") { + + if (fd < 0) { + ALOGW("%s: File descriptor out of range (%d)", __FUNCTION__, fd); + } + + // -- e.g. '%-4s%s\n' for indent=4 + snprintf(mFormatString, sizeof(mFormatString), "%%-%us%%s\n", mIndent); +} + +void FdPrinter::printLine(const char* string) { + if (string == NULL) { + ALOGW("%s: NULL string passed in", __FUNCTION__); + return; + } else if (mFd < 0) { + ALOGW("%s: File descriptor out of range (%d)", __FUNCTION__, mFd); + return; + } + + fdprintf(mFd, mFormatString, mPrefix, string); +} + +/* + * Implementation of String8Printer + */ +String8Printer::String8Printer(String8* target, const char* prefix) : + mTarget(target), + mPrefix(prefix ?: "") { + + if (target == NULL) { + ALOGW("%s: Target string was NULL", __FUNCTION__); + } +} + +void String8Printer::printLine(const char* string) { + if (string == NULL) { + ALOGW("%s: NULL string passed in", __FUNCTION__); + return; + } else if (mTarget == NULL) { + ALOGW("%s: Target string was NULL", __FUNCTION__); + return; + } + + mTarget->append(string); + mTarget->append("\n"); +} + +/* + * Implementation of PrefixPrinter + */ +PrefixPrinter::PrefixPrinter(Printer& printer, const char* prefix) : + mPrinter(printer), mPrefix(prefix ?: "") { +} + +void PrefixPrinter::printLine(const char* string) { + mPrinter.printFormatLine("%s%s", mPrefix, string); +} + +}; //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 @@ +/* + * 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. + */ + +#define LOG_TAG "ProcessCallStack" +// #define LOG_NDEBUG 0 + +#include +#include +#include + +#include +#include +#include +#include + +namespace android { + +enum { + // Max sizes for various dynamically generated strings + MAX_TIME_STRING = 64, + MAX_PROC_PATH = 1024, + + // Dump related prettiness constants + IGNORE_DEPTH_CURRENT_THREAD = 2, +}; + +static const char* CALL_STACK_PREFIX = " "; +static const char* PATH_THREAD_NAME = "/proc/self/task/%d/comm"; +static const char* PATH_SELF_TASK = "/proc/self/task"; + +static void dumpProcessHeader(Printer& printer, pid_t pid, const char* timeStr) { + if (timeStr == NULL) { + ALOGW("%s: timeStr was NULL", __FUNCTION__); + return; + } + + char path[PATH_MAX]; + char procNameBuf[MAX_PROC_PATH]; + char* procName = NULL; + FILE* fp; + + snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); + if ((fp = fopen(path, "r"))) { + procName = fgets(procNameBuf, sizeof(procNameBuf), fp); + fclose(fp); + } + + if (!procName) { + procName = const_cast(""); + } + + printer.printLine(); + printer.printLine(); + printer.printFormatLine("----- pid %d at %s -----", pid, timeStr); + printer.printFormatLine("Cmd line: %s", procName); +} + +static void dumpProcessFooter(Printer& printer, pid_t pid) { + printer.printLine(); + printer.printFormatLine("----- end %d -----", pid); + printer.printLine(); +} + +static String8 getThreadName(pid_t tid) { + char path[PATH_MAX]; + char* procName = NULL; + char procNameBuf[MAX_PROC_PATH]; + FILE* fp; + + snprintf(path, sizeof(path), PATH_THREAD_NAME, tid); + if ((fp = fopen(path, "r"))) { + procName = fgets(procNameBuf, sizeof(procNameBuf), fp); + fclose(fp); + } else { + ALOGE("%s: Failed to open %s", __FUNCTION__, path); + } + + // Strip ending newline + strtok(procName, "\n"); + + return String8(procName); +} + +static String8 getTimeString(struct tm tm) { + char timestr[MAX_TIME_STRING]; + // i.e. '2013-10-22 14:42:05' + strftime(timestr, sizeof(timestr), "%F %T", &tm); + + return String8(timestr); +} + +/* + * Implementation of ProcessCallStack + */ +ProcessCallStack::ProcessCallStack() { +} + +ProcessCallStack::ProcessCallStack(const ProcessCallStack& rhs) : + mThreadMap(rhs.mThreadMap), + mTimeUpdated(rhs.mTimeUpdated) { +} + +ProcessCallStack::~ProcessCallStack() { +} + +void ProcessCallStack::clear() { + mThreadMap.clear(); + mTimeUpdated = tm(); +} + +void ProcessCallStack::update(int32_t maxDepth) { + DIR *dp; + struct dirent *ep; + struct dirent entry; + + dp = opendir(PATH_SELF_TASK); + if (dp == NULL) { + ALOGE("%s: Failed to update the process's call stacks (errno = %d, '%s')", + __FUNCTION__, errno, strerror(errno)); + return; + } + + pid_t selfPid = getpid(); + + clear(); + + // Get current time. + { + time_t t = time(NULL); + struct tm tm; + localtime_r(&t, &tm); + + mTimeUpdated = tm; + } + + /* + * Each tid is a directory inside of /proc/self/task + * - Read every file in directory => get every tid + */ + int code; + while ((code = readdir_r(dp, &entry, &ep)) == 0 && ep != NULL) { + pid_t tid = -1; + sscanf(ep->d_name, "%d", &tid); + + if (tid < 0) { + // Ignore '.' and '..' + ALOGV("%s: Failed to read tid from %s/%s", + __FUNCTION__, PATH_SELF_TASK, ep->d_name); + continue; + } + + ssize_t idx = mThreadMap.add(tid, ThreadInfo()); + if (idx < 0) { // returns negative error value on error + ALOGE("%s: Failed to add new ThreadInfo (errno = %zd, '%s')", + __FUNCTION__, idx, strerror(-idx)); + continue; + } + + ThreadInfo& threadInfo = mThreadMap.editValueAt(static_cast(idx)); + + /* + * Ignore CallStack::update and ProcessCallStack::update for current thread + * - Every other thread doesn't need this since we call update off-thread + */ + int ignoreDepth = (selfPid == tid) ? IGNORE_DEPTH_CURRENT_THREAD : 0; + + // Update thread's call stacks + CallStack& cs = threadInfo.callStack; + cs.update(ignoreDepth, maxDepth, tid); + + // Read/save thread name + threadInfo.threadName = getThreadName(tid); + + ALOGV("%s: Got call stack for tid %d (size %zu)", + __FUNCTION__, tid, cs.size()); + } + if (code != 0) { // returns positive error value on error + ALOGE("%s: Failed to readdir from %s (errno = %d, '%s')", + __FUNCTION__, PATH_SELF_TASK, -code, strerror(code)); + } + + closedir(dp); +} + +void ProcessCallStack::log(const char* logtag, android_LogPriority priority, + const char* prefix) const { + LogPrinter printer(logtag, priority, prefix, /*ignoreBlankLines*/false); + print(printer); +} + +void ProcessCallStack::print(Printer& printer) const { + /* + * Print the header/footer with the regular printer. + * Print the callstack with an additional two spaces as the prefix for legibility. + */ + PrefixPrinter csPrinter(printer, CALL_STACK_PREFIX); + printInternal(printer, csPrinter); +} + +void ProcessCallStack::printInternal(Printer& printer, Printer& csPrinter) const { + dumpProcessHeader(printer, getpid(), + getTimeString(mTimeUpdated).string()); + + for (size_t i = 0; i < mThreadMap.size(); ++i) { + pid_t tid = mThreadMap.keyAt(i); + const ThreadInfo& threadInfo = mThreadMap.valueAt(i); + const CallStack& cs = threadInfo.callStack; + const String8& threadName = threadInfo.threadName; + + printer.printLine(""); + printer.printFormatLine("\"%s\" sysTid=%d", threadName.string(), tid); + + cs.print(csPrinter); + } + + dumpProcessFooter(printer, getpid()); +} + +void ProcessCallStack::dump(int fd, int indent, const char* prefix) const { + + if (indent < 0) { + ALOGW("%s: Bad indent (%d)", __FUNCTION__, indent); + return; + } + + FdPrinter printer(fd, static_cast(indent), prefix); + print(printer); +} + +String8 ProcessCallStack::toString(const char* prefix) const { + + String8 dest; + String8Printer printer(&dest, prefix); + print(printer); + + return dest; +} + +size_t ProcessCallStack::size() const { + return mThreadMap.size(); +} + +}; //namespace android From 81f2c3d2117cfe7307ee6efbd82567bd02950965 Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Wed, 30 Oct 2013 16:01:54 -0700 Subject: [PATCH 4/6] utils: Fix broken build Bug: 11324229 Change-Id: I7e4f514c5531e4c0c11bb0ba5d67e4dabbcd5792 --- libutils/ProcessCallStack.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp index ed35237a0..e202b9c1e 100644 --- a/libutils/ProcessCallStack.cpp +++ b/libutils/ProcessCallStack.cpp @@ -26,6 +26,8 @@ #include #include +#include + namespace android { enum { From e65b7ea8801145626504c724c28aedd0e5038a28 Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Wed, 30 Oct 2013 18:09:52 -0700 Subject: [PATCH 5/6] utils: Fix broken sdk build on windows Bug: 11324229 Change-Id: Ia50e79b5e2430faea77b0c98902e8e018fb9ceff --- libutils/Printer.cpp | 8 ++++++++ libutils/ProcessCallStack.cpp | 2 ++ 2 files changed, 10 insertions(+) diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp index b062ef0a7..ac729e05c 100644 --- a/libutils/Printer.cpp +++ b/libutils/Printer.cpp @@ -47,10 +47,16 @@ void Printer::printFormatLine(const char* format, ...) { va_start(arglist, format); char* formattedString; + +#ifndef USE_MINGW if (vasprintf(&formattedString, format, arglist) < 0) { // returns -1 on error ALOGE("%s: Failed to format string", __FUNCTION__); return; } +#else + return; +#endif + va_end(arglist); printLine(formattedString); @@ -113,7 +119,9 @@ void FdPrinter::printLine(const char* string) { return; } +#ifndef USE_MINGW fdprintf(mFd, mFormatString, mPrefix, string); +#endif } /* diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp index e202b9c1e..f9340c5b0 100644 --- a/libutils/ProcessCallStack.cpp +++ b/libutils/ProcessCallStack.cpp @@ -140,6 +140,7 @@ void ProcessCallStack::update(int32_t maxDepth) { clear(); // Get current time. +#ifndef USE_MINGW { time_t t = time(NULL); struct tm tm; @@ -193,6 +194,7 @@ void ProcessCallStack::update(int32_t maxDepth) { ALOGE("%s: Failed to readdir from %s (errno = %d, '%s')", __FUNCTION__, PATH_SELF_TASK, -code, strerror(code)); } +#endif closedir(dp); } From eb0eb4f79fca083009aa7a6b6e28ddcdbcbd1214 Mon Sep 17 00:00:00 2001 From: Shuo Gao Date: Thu, 17 Oct 2013 11:36:11 +0800 Subject: [PATCH 6/6] fix corruption in Vector<> when malloc falied 1. When alloc or realloc failed in the function SharedBuffer::editResize, it would return a NULL pointer, then mStorage would update to be 1 by SharedBuffer::data() if no pointer check here, which is an obviously wrong address, and would cause corruption when used it e.g. in capacity(). So add the pointer check here for the return value of SharedBuffer::editResize, if it's NULL do not use it to update mStorage, to avoid the value of mStorage polluted. 2. when alloc or realloc falied in _grow & _shrink function, mStorage keep the original value, so mCount should not be updated here. Otherwise, mStorage might be 0 but mCount>0, so a corruption would happend when it try to delete items from the Vector since mCount>0. Change-Id: I7c3814e843c459834ca5eed392e8d63d1cb7d2d8 Signed-off-by: Shuo Gao Signed-off-by: Jian Luo Signed-off-by: Bruce Beare Signed-off-by: Jack Ren Author-tracking-BZ: 139626 --- libutils/VectorImpl.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp index 5a79647cb..30ca6635e 100644 --- a/libutils/VectorImpl.cpp +++ b/libutils/VectorImpl.cpp @@ -384,7 +384,11 @@ void* VectorImpl::_grow(size_t where, size_t amount) { const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage); SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize); - mStorage = sb->data(); + if (sb) { + mStorage = sb->data(); + } else { + return NULL; + } } else { SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize); if (sb) { @@ -399,6 +403,8 @@ void* VectorImpl::_grow(size_t where, size_t amount) } release_storage(); mStorage = const_cast(array); + } else { + return NULL; } } } else { @@ -436,7 +442,11 @@ void VectorImpl::_shrink(size_t where, size_t amount) { const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage); SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize); - mStorage = sb->data(); + if (sb) { + mStorage = sb->data(); + } else { + return; + } } else { SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize); if (sb) { @@ -451,6 +461,8 @@ void VectorImpl::_shrink(size_t where, size_t amount) } release_storage(); mStorage = const_cast(array); + } else{ + return; } } } else {