diff options
80 files changed, 2074 insertions, 1698 deletions
diff --git a/adb/Android.mk b/adb/Android.mk index 4f19d47..3733ae3 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -161,7 +161,6 @@ ifeq ($(USE_SYSDEPS_WIN32),) LOCAL_STATIC_LIBRARIES += libcutils endif -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_HOST_EXECUTABLE) $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE)) @@ -221,6 +220,4 @@ LOCAL_STATIC_LIBRARIES := \ libselinux \ libext4_utils_static \ -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - include $(BUILD_EXECUTABLE) diff --git a/adb/commandline.cpp b/adb/commandline.cpp index f9ca5ed..34efefe 100644 --- a/adb/commandline.cpp +++ b/adb/commandline.cpp @@ -256,29 +256,25 @@ void stdin_raw_restore(int fd); } #else -static struct termios tio_save; +static termios g_saved_terminal_state; -static void stdin_raw_init(int fd) -{ - struct termios tio; +static void stdin_raw_init(int fd) { + if (tcgetattr(fd, &g_saved_terminal_state)) return; - if(tcgetattr(fd, &tio)) return; - if(tcgetattr(fd, &tio_save)) return; + termios tio; + if (tcgetattr(fd, &tio)) return; - tio.c_lflag = 0; /* disable CANON, ECHO*, etc */ + cfmakeraw(&tio); - /* no timeout but request at least one character per read */ + // No timeout but request at least one character per read. tio.c_cc[VTIME] = 0; tio.c_cc[VMIN] = 1; - tcsetattr(fd, TCSANOW, &tio); - tcflush(fd, TCIFLUSH); + tcsetattr(fd, TCSAFLUSH, &tio); } -static void stdin_raw_restore(int fd) -{ - tcsetattr(fd, TCSANOW, &tio_save); - tcflush(fd, TCIFLUSH); +static void stdin_raw_restore(int fd) { + tcsetattr(fd, TCSAFLUSH, &g_saved_terminal_state); } #endif diff --git a/adb/transport.cpp b/adb/transport.cpp index 0a960ff..4b9eeeb 100644 --- a/adb/transport.cpp +++ b/adb/transport.cpp @@ -772,7 +772,7 @@ void remove_transport_disconnect(atransport* t, adisconnect* dis) } static int qual_match(const char *to_test, - const char *prefix, const char *qual, int sanitize_qual) + const char *prefix, const char *qual, bool sanitize_qual) { if (!to_test || !*to_test) /* Return true if both the qual and to_test are null strings. */ @@ -790,7 +790,7 @@ static int qual_match(const char *to_test, while (*qual) { char ch = *qual++; - if (sanitize_qual && isalnum(ch)) + if (sanitize_qual && !isalnum(ch)) ch = '_'; if (ch != *to_test++) return 0; @@ -823,9 +823,9 @@ retry: if (serial) { if ((t->serial && !strcmp(serial, t->serial)) || (t->devpath && !strcmp(serial, t->devpath)) || - qual_match(serial, "product:", t->product, 0) || - qual_match(serial, "model:", t->model, 1) || - qual_match(serial, "device:", t->device, 0)) { + qual_match(serial, "product:", t->product, false) || + qual_match(serial, "model:", t->model, true) || + qual_match(serial, "device:", t->device, false)) { if (result) { if (error_out) *error_out = "more than one device"; @@ -918,20 +918,17 @@ static const char *statename(atransport *t) } static void add_qual(char **buf, size_t *buf_size, - const char *prefix, const char *qual, int sanitize_qual) + const char *prefix, const char *qual, bool sanitize_qual) { - size_t len; - int prefix_len; - if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual) return; - len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual); + int prefix_len; + size_t len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual); if (sanitize_qual) { - char *cp; - for (cp = *buf + prefix_len; cp < *buf + len; cp++) { - if (isalnum(*cp)) + for (char* cp = *buf + prefix_len; cp < *buf + len; cp++) { + if (!isalnum(*cp)) *cp = '_'; } } @@ -956,10 +953,10 @@ static size_t format_transport(atransport *t, char *buf, size_t bufsize, remaining -= len; buf += len; - add_qual(&buf, &remaining, " ", t->devpath, 0); - add_qual(&buf, &remaining, " product:", t->product, 0); - add_qual(&buf, &remaining, " model:", t->model, 1); - add_qual(&buf, &remaining, " device:", t->device, 0); + add_qual(&buf, &remaining, " ", t->devpath, false); + add_qual(&buf, &remaining, " product:", t->product, false); + add_qual(&buf, &remaining, " model:", t->model, true); + add_qual(&buf, &remaining, " device:", t->device, false); len = snprintf(buf, remaining, "\n"); remaining -= len; diff --git a/base/CPPLINT.cfg b/base/CPPLINT.cfg index a61c08d..d94a89c 100644 --- a/base/CPPLINT.cfg +++ b/base/CPPLINT.cfg @@ -1,2 +1,2 @@ set noparent -filter=-build/header_guard,-build/include,-build/c++11 +filter=-build/header_guard,-build/include,-build/c++11,-whitespace/operators diff --git a/base/include/base/logging.h b/base/include/base/logging.h index 5e115fe..230adb8 100644 --- a/base/include/base/logging.h +++ b/base/include/base/logging.h @@ -17,6 +17,7 @@ #ifndef BASE_LOGGING_H #define BASE_LOGGING_H +#include <functional> #include <memory> #include <ostream> @@ -34,6 +35,33 @@ enum LogSeverity { FATAL, }; +enum LogId { + DEFAULT, + MAIN, + SYSTEM, +}; + +typedef std::function<void(LogId, LogSeverity, const char*, const char*, + unsigned int, const char*)> LogFunction; + +extern void StderrLogger(LogId, LogSeverity, const char*, const char*, + unsigned int, const char*); + +#ifdef __ANDROID__ +// We expose this even though it is the default because a user that wants to +// override the default log buffer will have to construct this themselves. +class LogdLogger { + public: + explicit LogdLogger(LogId default_log_id = android::base::MAIN); + + void operator()(LogId, LogSeverity, const char* tag, const char* file, + unsigned int line, const char* message); + + private: + LogId default_log_id_; +}; +#endif + // Configure logging based on ANDROID_LOG_TAGS environment variable. // We need to parse a string that looks like // @@ -42,33 +70,39 @@ enum LogSeverity { // The tag (or '*' for the global level) comes first, followed by a colon and a // letter indicating the minimum priority level we're expected to log. This can // be used to reveal or conceal logs with specific tags. -extern void InitLogging(char* argv[]); - -// Returns the command line used to invoke the current tool or nullptr if -// InitLogging hasn't been performed. -extern const char* GetCmdLine(); +extern void InitLogging(char* argv[], LogFunction&& logger); -// The command used to start the program, such as "/system/bin/dalvikvm". If -// InitLogging hasn't been performed then just returns "unknown" -extern const char* ProgramInvocationName(); +// Configures logging using the default logger (logd for the device, stderr for +// the host). +extern void InitLogging(char* argv[]); -// A short version of the command used to start the program, such as "dalvikvm". -// If InitLogging hasn't been performed then just returns "unknown" -extern const char* ProgramInvocationShortName(); +// Replace the current logger. +extern void SetLogger(LogFunction&& logger); // Logs a message to logcat on Android otherwise to stderr. If the severity is // FATAL it also causes an abort. For example: // // LOG(FATAL) << "We didn't expect to reach here"; -#define LOG(severity) \ - ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::severity, \ - -1).stream() +#define LOG(severity) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \ + ::android::base::severity, -1).stream() + +// Logs a message to logcat with the specified log ID on Android otherwise to +// stderr. If the severity is FATAL it also causes an abort. +#define LOG_TO(dest, severity) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \ + ::android::base::severity, -1).stream() // A variant of LOG that also logs the current errno value. To be used when // library calls fail. -#define PLOG(severity) \ - ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::severity, \ - errno).stream() +#define PLOG(severity) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \ + ::android::base::severity, errno).stream() + +// Behaves like PLOG, but logs to the specified log ID. +#define PLOG_TO(dest, severity) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \ + ::android::base::severity, errno).stream() // Marker that code is yet to be implemented. #define UNIMPLEMENTED(level) \ @@ -82,18 +116,18 @@ extern const char* ProgramInvocationShortName(); // "Check failed: false == true". #define CHECK(x) \ if (UNLIKELY(!(x))) \ - ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, \ - -1).stream() \ - << "Check failed: " #x << " " + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \ + ::android::base::FATAL, -1).stream() \ + << "Check failed: " #x << " " // Helper for CHECK_xx(x,y) macros. -#define CHECK_OP(LHS, RHS, OP) \ - for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS); \ - UNLIKELY(!(_values.lhs OP _values.rhs)); \ - /* empty */) \ - ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, -1) \ - .stream() \ - << "Check failed: " << #LHS << " " << #OP << " " << #RHS \ +#define CHECK_OP(LHS, RHS, OP) \ + for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS); \ + UNLIKELY(!(_values.lhs OP _values.rhs)); \ + /* empty */) \ + ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \ + ::android::base::FATAL, -1).stream() \ + << "Check failed: " << #LHS << " " << #OP << " " << #RHS \ << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") " // Check whether a condition holds between x and y, LOG(FATAL) if not. The value @@ -228,8 +262,8 @@ class LogMessageData; // of a CHECK. The destructor will abort if the severity is FATAL. class LogMessage { public: - LogMessage(const char* file, unsigned int line, LogSeverity severity, - int error); + LogMessage(const char* file, unsigned int line, LogId id, + LogSeverity severity, int error); ~LogMessage(); @@ -238,12 +272,8 @@ class LogMessage { std::ostream& stream(); // The routine that performs the actual logging. - static void LogLine(const char* file, unsigned int line, LogSeverity severity, - const char* msg); - - // A variant of the above for use with little stack. - static void LogLineLowStack(const char* file, unsigned int line, - LogSeverity severity, const char* msg); + static void LogLine(const char* file, unsigned int line, LogId id, + LogSeverity severity, const char* msg); private: const std::unique_ptr<LogMessageData> data_; diff --git a/base/logging.cpp b/base/logging.cpp index 38ee2af..0142b70 100644 --- a/base/logging.cpp +++ b/base/logging.cpp @@ -16,11 +16,21 @@ #include "base/logging.h" +#include <libgen.h> + +// For getprogname(3) or program_invocation_short_name. +#if defined(__ANDROID__) || defined(__APPLE__) +#include <stdlib.h> +#elif defined(__GLIBC__) +#include <errno.h> +#endif + #include <iostream> #include <limits> #include <mutex> #include <sstream> #include <string> +#include <utility> #include <vector> #include "base/strings.h" @@ -40,49 +50,96 @@ namespace base { static std::mutex logging_lock; +#ifdef __ANDROID__ +static LogFunction gLogger = LogdLogger(); +#else +static LogFunction gLogger = StderrLogger; +#endif + +static bool gInitialized = false; static LogSeverity gMinimumLogSeverity = INFO; -static std::unique_ptr<std::string> gCmdLine; static std::unique_ptr<std::string> gProgramInvocationName; -static std::unique_ptr<std::string> gProgramInvocationShortName; -const char* GetCmdLine() { - return (gCmdLine.get() != nullptr) ? gCmdLine->c_str() : nullptr; +#if defined(__GLIBC__) +static const char* getprogname() { + return program_invocation_short_name; } +#endif + +static const char* ProgramInvocationName() { + if (gProgramInvocationName == nullptr) { + gProgramInvocationName.reset(new std::string(getprogname())); + } -const char* ProgramInvocationName() { - return (gProgramInvocationName.get() != nullptr) - ? gProgramInvocationName->c_str() - : "unknown"; + return gProgramInvocationName->c_str(); } -const char* ProgramInvocationShortName() { - return (gProgramInvocationShortName.get() != nullptr) - ? gProgramInvocationShortName->c_str() - : "unknown"; +void StderrLogger(LogId, LogSeverity severity, const char*, const char* file, + unsigned int line, const char* message) { + static const char* log_characters = "VDIWEF"; + CHECK_EQ(strlen(log_characters), FATAL + 1U); + char severity_char = log_characters[severity]; + fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(), + severity_char, getpid(), gettid(), file, line, message); +} + + +#ifdef __ANDROID__ +LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) { +} + +static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { + ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, + ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, +}; +static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1, + "Mismatch in size of kLogSeverityToAndroidLogPriority and values " + "in LogSeverity"); + +static const log_id kLogIdToAndroidLogId[] = { + LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM, +}; +static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1, + "Mismatch in size of kLogIdToAndroidLogId and values in LogId"); + +void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag, + const char* file, unsigned int line, + const char* message) { + int priority = kLogSeverityToAndroidLogPriority[severity]; + if (id == DEFAULT) { + id = default_log_id_; + } + + log_id lg_id = kLogIdToAndroidLogId[id]; + + if (priority == ANDROID_LOG_FATAL) { + __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line, + message); + } else { + __android_log_buf_print(lg_id, priority, tag, "%s", message); + } +} +#endif + +void InitLogging(char* argv[], LogFunction&& logger) { + SetLogger(std::forward<LogFunction>(logger)); + InitLogging(argv); } void InitLogging(char* argv[]) { - if (gCmdLine.get() != nullptr) { + if (gInitialized) { return; } + gInitialized = true; + // Stash the command line for later use. We can use /proc/self/cmdline on // Linux to recover this, but we don't have that luxury on the Mac, and there // are a couple of argv[0] variants that are commonly used. if (argv != nullptr) { - gCmdLine.reset(new std::string(argv[0])); - for (size_t i = 1; argv[i] != nullptr; ++i) { - gCmdLine->append(" "); - gCmdLine->append(argv[i]); - } - gProgramInvocationName.reset(new std::string(argv[0])); - const char* last_slash = strrchr(argv[0], '/'); - gProgramInvocationShortName.reset( - new std::string((last_slash != nullptr) ? last_slash + 1 : argv[0])); - } else { - // TODO: fall back to /proc/self/cmdline when argv is NULL on Linux. - gCmdLine.reset(new std::string("<unset>")); + gProgramInvocationName.reset(new std::string(basename(argv[0]))); } + const char* tags = getenv("ANDROID_LOG_TAGS"); if (tags == nullptr) { return; @@ -124,13 +181,22 @@ void InitLogging(char* argv[]) { } } +void SetLogger(LogFunction&& logger) { + std::lock_guard<std::mutex> lock(logging_lock); + gLogger = std::move(logger); +} + // This indirection greatly reduces the stack impact of having lots of // checks/logging in a function. class LogMessageData { public: - LogMessageData(const char* file, unsigned int line, LogSeverity severity, - int error) - : file_(file), line_number_(line), severity_(severity), error_(error) { + LogMessageData(const char* file, unsigned int line, LogId id, + LogSeverity severity, int error) + : file_(file), + line_number_(line), + id_(id), + severity_(severity), + error_(error) { const char* last_slash = strrchr(file, '/'); file = (last_slash == nullptr) ? file : last_slash + 1; } @@ -147,6 +213,10 @@ class LogMessageData { return severity_; } + LogId GetId() const { + return id_; + } + int GetError() const { return error_; } @@ -163,15 +233,16 @@ class LogMessageData { std::ostringstream buffer_; const char* const file_; const unsigned int line_number_; + const LogId id_; const LogSeverity severity_; const int error_; DISALLOW_COPY_AND_ASSIGN(LogMessageData); }; -LogMessage::LogMessage(const char* file, unsigned int line, +LogMessage::LogMessage(const char* file, unsigned int line, LogId id, LogSeverity severity, int error) - : data_(new LogMessageData(file, line, severity, error)) { + : data_(new LogMessageData(file, line, id, severity, error)) { } LogMessage::~LogMessage() { @@ -185,22 +256,18 @@ LogMessage::~LogMessage() { } std::string msg(data_->ToString()); - // Do the actual logging with the lock held. - { - std::lock_guard<std::mutex> lock(logging_lock); - if (msg.find('\n') == std::string::npos) { - LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), - msg.c_str()); - } else { - msg += '\n'; - size_t i = 0; - while (i < msg.size()) { - size_t nl = msg.find('\n', i); - msg[nl] = '\0'; - LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), - &msg[i]); - i = nl + 1; - } + if (msg.find('\n') == std::string::npos) { + LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), + data_->GetSeverity(), msg.c_str()); + } else { + msg += '\n'; + size_t i = 0; + while (i < msg.size()) { + size_t nl = msg.find('\n', i); + msg[nl] = '\0'; + LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), + data_->GetSeverity(), &msg[i]); + i = nl + 1; } } @@ -217,76 +284,11 @@ std::ostream& LogMessage::stream() { return data_->GetBuffer(); } -#ifdef __ANDROID__ -static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { - ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, - ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL}; -static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1, - "Mismatch in size of kLogSeverityToAndroidLogPriority and values " - "in LogSeverity"); -#endif - -void LogMessage::LogLine(const char* file, unsigned int line, - LogSeverity log_severity, const char* message) { -#ifdef __ANDROID__ - const char* tag = ProgramInvocationShortName(); - int priority = kLogSeverityToAndroidLogPriority[log_severity]; - if (priority == ANDROID_LOG_FATAL) { - LOG_PRI(priority, tag, "%s:%u] %s", file, line, message); - } else { - LOG_PRI(priority, tag, "%s", message); - } -#else - static const char* log_characters = "VDIWEF"; - CHECK_EQ(strlen(log_characters), FATAL + 1U); - char severity = log_characters[log_severity]; - fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationShortName(), - severity, getpid(), gettid(), file, line, message); -#endif -} - -void LogMessage::LogLineLowStack(const char* file, unsigned int line, - LogSeverity log_severity, const char* message) { -#ifdef __ANDROID__ - // Use android_writeLog() to avoid stack-based buffers used by - // android_printLog(). - const char* tag = ProgramInvocationShortName(); - int priority = kLogSeverityToAndroidLogPriority[log_severity]; - char* buf = nullptr; - size_t buf_size = 0u; - if (priority == ANDROID_LOG_FATAL) { - // Allocate buffer for snprintf(buf, buf_size, "%s:%u] %s", file, line, - // message) below. If allocation fails, fall back to printing only the - // message. - buf_size = strlen(file) + 1 /* ':' */ + - std::numeric_limits<typeof(line)>::max_digits10 + 2 /* "] " */ + - strlen(message) + 1 /* terminating 0 */; - buf = reinterpret_cast<char*>(malloc(buf_size)); - } - if (buf != nullptr) { - snprintf(buf, buf_size, "%s:%u] %s", file, line, message); - android_writeLog(priority, tag, buf); - free(buf); - } else { - android_writeLog(priority, tag, message); - } -#else - static const char* log_characters = "VDIWEF"; - CHECK_EQ(strlen(log_characters), FATAL + 1U); - - const char* program_name = ProgramInvocationShortName(); - write(STDERR_FILENO, program_name, strlen(program_name)); - write(STDERR_FILENO, " ", 1); - write(STDERR_FILENO, &log_characters[log_severity], 1); - write(STDERR_FILENO, " ", 1); - // TODO: pid and tid. - write(STDERR_FILENO, file, strlen(file)); - // TODO: line. - UNUSED(line); - write(STDERR_FILENO, "] ", 2); - write(STDERR_FILENO, message, strlen(message)); - write(STDERR_FILENO, "\n", 1); -#endif +void LogMessage::LogLine(const char* file, unsigned int line, LogId id, + LogSeverity severity, const char* message) { + const char* tag = ProgramInvocationName(); + std::lock_guard<std::mutex> lock(logging_lock); + gLogger(id, severity, tag, file, line, message); } ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) { diff --git a/base/logging_test.cpp b/base/logging_test.cpp index 0a03e38..d947c1d 100644 --- a/base/logging_test.cpp +++ b/base/logging_test.cpp @@ -61,7 +61,7 @@ class CapturedStderr { int old_stderr_; }; -HOST_TEST(logging, CHECK) { +TEST(logging, CHECK) { ASSERT_DEATH(CHECK(false), "Check failed: false "); CHECK(true); @@ -82,7 +82,7 @@ std::string make_log_pattern(android::base::LogSeverity severity, log_char, message); } -HOST_TEST(logging, LOG) { +TEST(logging, LOG) { ASSERT_DEATH(LOG(FATAL) << "foobar", "foobar"); { @@ -136,7 +136,7 @@ HOST_TEST(logging, LOG) { } } -HOST_TEST(logging, PLOG) { +TEST(logging, PLOG) { { CapturedStderr cap; errno = ENOENT; @@ -152,7 +152,7 @@ HOST_TEST(logging, PLOG) { } } -HOST_TEST(logging, UNIMPLEMENTED) { +TEST(logging, UNIMPLEMENTED) { { CapturedStderr cap; errno = ENOENT; diff --git a/base/test_main.cpp b/base/test_main.cpp index c49ca4b..546923d 100644 --- a/base/test_main.cpp +++ b/base/test_main.cpp @@ -20,6 +20,6 @@ int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); - android::base::InitLogging(argv); + android::base::InitLogging(argv, android::base::StderrLogger); return RUN_ALL_TESTS(); } diff --git a/cpio/Android.mk b/cpio/Android.mk index 575beb2..b9d18ba 100644 --- a/cpio/Android.mk +++ b/cpio/Android.mk @@ -10,6 +10,8 @@ LOCAL_MODULE := mkbootfs LOCAL_CFLAGS := -Werror +LOCAL_STATIC_LIBRARIES := libcutils + include $(BUILD_HOST_EXECUTABLE) $(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE)) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 6dc7d34..e139bcd 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -538,7 +538,7 @@ void queue_info_dump(void) static struct sparse_file **load_sparse_files(int fd, int max_size) { - struct sparse_file* s = sparse_file_import_auto(fd, false); + struct sparse_file* s = sparse_file_import_auto(fd, false, true); if (!s) { die("cannot sparse read file\n"); } diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk index 61bf1ee..1179eaa 100644 --- a/fs_mgr/Android.mk +++ b/fs_mgr/Android.mk @@ -35,6 +35,7 @@ LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static +LOCAL_CXX_STL := libc++_static LOCAL_CFLAGS := -Werror diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c index d4daed6..273a2ec 100644 --- a/fs_mgr/fs_mgr.c +++ b/fs_mgr/fs_mgr.c @@ -31,6 +31,7 @@ #include <dirent.h> #include <ext4.h> #include <ext4_sb.h> +#include <ext4_crypt.h> #include <linux/loop.h> #include <private/android_filesystem_config.h> @@ -428,6 +429,73 @@ out: return ret; } +// Check to see if a mountable volume has encryption requirements +static int handle_encryptable(struct fstab *fstab, const struct fstab_rec* rec) +{ + /* If this is block encryptable, need to trigger encryption */ + if ( (rec->fs_mgr_flags & MF_FORCECRYPT) + || (device_is_force_encrypted() && fs_mgr_is_encryptable(rec))) { + if (umount(rec->mount_point) == 0) { + return FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION; + } else { + WARNING("Could not umount %s (%s) - allow continue unencrypted\n", + rec->mount_point, strerror(errno)); + return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED; + } + } + + // Deal with file level encryption + if (rec->fs_mgr_flags & MF_FILEENCRYPTION) { + // Default or not yet initialized encryption requires no more work here + if (!e4crypt_non_default_key(rec->mount_point)) { + INFO("%s is default file encrypted\n", rec->mount_point); + return FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED; + } + + INFO("%s is non-default file encrypted\n", rec->mount_point); + + // Uses non-default key, so must unmount and set up temp file system + if (umount(rec->mount_point)) { + ERROR("Failed to umount %s - rebooting\n", rec->mount_point); + return FS_MGR_MNTALL_FAIL; + } + + if (fs_mgr_do_tmpfs_mount(rec->mount_point) != 0) { + ERROR("Failed to mount a tmpfs at %s\n", rec->mount_point); + return FS_MGR_MNTALL_FAIL; + } + + // Mount data temporarily so we can access unencrypted dir + char tmp_mnt[PATH_MAX]; + strlcpy(tmp_mnt, rec->mount_point, sizeof(tmp_mnt)); + strlcat(tmp_mnt, "/tmp_mnt", sizeof(tmp_mnt)); + if (mkdir(tmp_mnt, 0700)) { + ERROR("Failed to create temp mount point\n"); + return FS_MGR_MNTALL_FAIL; + } + + if (fs_mgr_do_mount(fstab, rec->mount_point, + rec->blk_device, tmp_mnt)) { + ERROR("Error temp mounting encrypted file system\n"); + return FS_MGR_MNTALL_FAIL; + } + + // Link it to the normal place so ext4_crypt functions work normally + strlcat(tmp_mnt, "/unencrypted", sizeof(tmp_mnt)); + char link_path[PATH_MAX]; + strlcpy(link_path, rec->mount_point, sizeof(link_path)); + strlcat(link_path, "/unencrypted", sizeof(link_path)); + if (symlink(tmp_mnt, link_path)) { + ERROR("Error creating symlink to unencrypted directory\n"); + return FS_MGR_MNTALL_FAIL; + } + + return FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED; + } + + return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED; +} + /* When multiple fstab records share the same mount_point, it will * try to mount each one in turn, and ignore any duplicates after a * first successful mount. @@ -490,25 +558,21 @@ int fs_mgr_mount_all(struct fstab *fstab) /* Deal with encryptability. */ if (!mret) { - /* If this is encryptable, need to trigger encryption */ - if ( (fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT) - || (device_is_force_encrypted() - && fs_mgr_is_encryptable(&fstab->recs[attempted_idx]))) { - if (umount(fstab->recs[attempted_idx].mount_point) == 0) { - if (encryptable == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) { - ERROR("Will try to encrypt %s %s\n", fstab->recs[attempted_idx].mount_point, - fstab->recs[attempted_idx].fs_type); - encryptable = FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION; - } else { - ERROR("Only one encryptable/encrypted partition supported\n"); - encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED; - } - } else { - WARNING("Could not umount %s (%s) - allow continue unencrypted\n", - fstab->recs[attempted_idx].mount_point, strerror(errno)); - continue; + int status = handle_encryptable(fstab, &fstab->recs[attempted_idx]); + + if (status == FS_MGR_MNTALL_FAIL) { + /* Fatal error - no point continuing */ + return status; + } + + if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) { + if (encryptable != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) { + // Log and continue + ERROR("Only one encryptable/encrypted partition supported\n"); } + encryptable = status; } + /* Success! Go get the next one */ continue; } diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c index 2c3c90d..8b0f714 100644 --- a/fs_mgr/fs_mgr_fstab.c +++ b/fs_mgr/fs_mgr_fstab.c @@ -61,6 +61,7 @@ static struct flag_list fs_mgr_flags[] = { { "check", MF_CHECK }, { "encryptable=",MF_CRYPT }, { "forceencrypt=",MF_FORCECRYPT }, + { "fileencryption",MF_FILEENCRYPTION }, { "nonremovable",MF_NONREMOVABLE }, { "voldmanaged=",MF_VOLDMANAGED}, { "length=", MF_LENGTH }, @@ -418,27 +419,32 @@ struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const ch return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path); } -int fs_mgr_is_voldmanaged(struct fstab_rec *fstab) +int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab) { return fstab->fs_mgr_flags & MF_VOLDMANAGED; } -int fs_mgr_is_nonremovable(struct fstab_rec *fstab) +int fs_mgr_is_nonremovable(const struct fstab_rec *fstab) { return fstab->fs_mgr_flags & MF_NONREMOVABLE; } -int fs_mgr_is_verified(struct fstab_rec *fstab) +int fs_mgr_is_verified(const struct fstab_rec *fstab) { return fstab->fs_mgr_flags & MF_VERIFY; } -int fs_mgr_is_encryptable(struct fstab_rec *fstab) +int fs_mgr_is_encryptable(const struct fstab_rec *fstab) { return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT); } -int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab) +int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab) +{ + return fstab->fs_mgr_flags & MF_FILEENCRYPTION; +} + +int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab) { return fstab->fs_mgr_flags & MF_NOEMULATEDSD; } diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index 88a1040..d56111a 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -76,6 +76,7 @@ #define MF_FORCECRYPT 0x400 #define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only external storage */ +#define MF_FILEENCRYPTION 0x2000 #define DM_BUF_SIZE 4096 diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 3286948..c58a888 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -74,10 +74,13 @@ typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab, struct fstab *fs_mgr_read_fstab(const char *fstab_path); void fs_mgr_free_fstab(struct fstab *fstab); +#define FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED 5 +#define FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED 4 #define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 3 #define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 2 #define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 1 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 0 +#define FS_MGR_MNTALL_FAIL -1 int fs_mgr_mount_all(struct fstab *fstab); #define FS_MGR_DOMNT_FAILED -1 @@ -94,11 +97,12 @@ int fs_mgr_add_entry(struct fstab *fstab, const char *mount_point, const char *fs_type, const char *blk_device); struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path); -int fs_mgr_is_voldmanaged(struct fstab_rec *fstab); -int fs_mgr_is_nonremovable(struct fstab_rec *fstab); -int fs_mgr_is_verified(struct fstab_rec *fstab); -int fs_mgr_is_encryptable(struct fstab_rec *fstab); -int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab); +int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab); +int fs_mgr_is_nonremovable(const struct fstab_rec *fstab); +int fs_mgr_is_verified(const struct fstab_rec *fstab); +int fs_mgr_is_encryptable(const struct fstab_rec *fstab); +int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab); +int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab); int fs_mgr_swapon_all(struct fstab *fstab); #ifdef __cplusplus } diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h index 8c39acb..290682a 100644 --- a/include/backtrace/Backtrace.h +++ b/include/backtrace/Backtrace.h @@ -44,9 +44,6 @@ struct backtrace_frame_data_t { uintptr_t func_offset; // pc relative to the start of the function, only valid if func_name is not NULL. }; -// Forward declarations. -class BacktraceImpl; - #if defined(__APPLE__) struct __darwin_ucontext; typedef __darwin_ucontext ucontext_t; @@ -72,7 +69,7 @@ public: virtual ~Backtrace(); // Get the current stack trace and store in the backtrace_ structure. - virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL); + virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0; // Get the function name and offset into the function given the pc. // If the string is empty, then no valid function name was found. @@ -95,9 +92,9 @@ public: virtual std::string FormatFrameData(size_t frame_num); virtual std::string FormatFrameData(const backtrace_frame_data_t* frame); - pid_t Pid() { return pid_; } - pid_t Tid() { return tid_; } - size_t NumFrames() { return frames_.size(); } + pid_t Pid() const { return pid_; } + pid_t Tid() const { return tid_; } + size_t NumFrames() const { return frames_.size(); } const backtrace_frame_data_t* GetFrame(size_t frame_num) { if (frame_num >= frames_.size()) { @@ -117,7 +114,11 @@ public: BacktraceMap* GetMap() { return map_; } protected: - Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map); + Backtrace(pid_t pid, pid_t tid, BacktraceMap* map); + + // The name returned is not demangled, GetFunctionName() takes care of + // demangling the name. + virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0; virtual bool VerifyReadWordArgs(uintptr_t ptr, word_t* out_value); @@ -130,10 +131,6 @@ protected: bool map_shared_; std::vector<backtrace_frame_data_t> frames_; - - BacktraceImpl* impl_; - - friend class BacktraceImpl; }; #endif // _BACKTRACE_BACKTRACE_H diff --git a/include/cutils/memory.h b/include/cutils/memory.h index e725cdd..4d26882 100644 --- a/include/cutils/memory.h +++ b/include/cutils/memory.h @@ -30,7 +30,7 @@ void android_memset16(uint16_t* dst, uint16_t value, size_t size); /* size is given in bytes and must be multiple of 4 */ void android_memset32(uint32_t* dst, uint32_t value, size_t size); -#if !HAVE_STRLCPY +#if defined(__GLIBC__) || defined(_WIN32) /* Declaration of strlcpy() for platforms that don't already have it. */ size_t strlcpy(char *dst, const char *src, size_t size); #endif diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h index c47588c..f8076ca 100644 --- a/include/cutils/sockets.h +++ b/include/cutils/sockets.h @@ -18,6 +18,7 @@ #define __CUTILS_SOCKETS_H #include <errno.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> @@ -46,30 +47,19 @@ extern "C" { */ static inline int android_get_control_socket(const char *name) { - char key[64] = ANDROID_SOCKET_ENV_PREFIX; - const char *val; - int fd; + char key[64]; + snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", name); - /* build our environment variable, counting cycles like a wolf ... */ -#if HAVE_STRLCPY - strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, - name, - sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); -#else /* for the host, which may lack the almightly strncpy ... */ - strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, - name, - sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); - key[sizeof(key)-1] = '\0'; -#endif - - val = getenv(key); - if (!val) + const char* val = getenv(key); + if (!val) { return -1; + } errno = 0; - fd = strtol(val, NULL, 10); - if (errno) + int fd = strtol(val, NULL, 10); + if (errno) { return -1; + } return fd; } diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h index 66f3637..aa1435a 100644 --- a/include/cutils/str_parms.h +++ b/include/cutils/str_parms.h @@ -18,6 +18,9 @@ #define __CUTILS_STR_PARMS_H #include <stdint.h> +#include <sys/cdefs.h> + +__BEGIN_DECLS struct str_parms; @@ -52,4 +55,6 @@ char *str_parms_to_str(struct str_parms *str_parms); /* debug */ void str_parms_dump(struct str_parms *str_parms); +__END_DECLS + #endif /* __CUTILS_STR_PARMS_H */ diff --git a/include/cutils/trace.h b/include/cutils/trace.h index 59ff6c1..9d039e6 100644 --- a/include/cutils/trace.h +++ b/include/cutils/trace.h @@ -80,7 +80,6 @@ __BEGIN_DECLS #error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h #endif -#ifdef HAVE_ANDROID_OS /** * Opens the trace file for writing and reads the property for initial tags. * The atrace.tags.enableflags property sets the tags to trace. @@ -248,19 +247,6 @@ static inline void atrace_int64(uint64_t tag, const char* name, int64_t value) } } -#else // not HAVE_ANDROID_OS - -#define ATRACE_INIT() -#define ATRACE_GET_ENABLED_TAGS() -#define ATRACE_ENABLED() 0 -#define ATRACE_BEGIN(name) -#define ATRACE_END() -#define ATRACE_ASYNC_BEGIN(name, cookie) -#define ATRACE_ASYNC_END(name, cookie) -#define ATRACE_INT(name, value) - -#endif // not HAVE_ANDROID_OS - __END_DECLS #endif // _LIBS_CUTILS_TRACE_H diff --git a/include/private/android_filesystem_capability.h b/include/private/android_filesystem_capability.h index 0505cda..b92d3db 100644 --- a/include/private/android_filesystem_capability.h +++ b/include/private/android_filesystem_capability.h @@ -105,7 +105,9 @@ struct vfs_cap_data { #define CAP_MAC_ADMIN 33 #define CAP_SYSLOG 34 #define CAP_WAKE_ALARM 35 -#define CAP_LAST_CAP CAP_WAKE_ALARM +#define CAP_BLOCK_SUSPEND 36 +#define CAP_AUDIT_READ 37 +#define CAP_LAST_CAP CAP_AUDIT_READ #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) #define CAP_TO_INDEX(x) ((x) >> 5) #define CAP_TO_MASK(x) (1 << ((x) & 31)) diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h index a3d11a7..fed81f8 100644 --- a/include/private/android_filesystem_config.h +++ b/include/private/android_filesystem_config.h @@ -22,8 +22,7 @@ #ifndef _ANDROID_FILESYSTEM_CONFIG_H_ #define _ANDROID_FILESYSTEM_CONFIG_H_ -#include <string.h> -#include <sys/stat.h> +#include <sys/cdefs.h> #include <sys/types.h> #include <stdint.h> @@ -114,6 +113,14 @@ #define AID_SHARED_GID_END 59999 /* start of gids for apps in each user to share */ #if !defined(EXCLUDE_FS_CONFIG_STRUCTURES) +/* + * Used in: + * bionic/libc/bionic/stubs.cpp + * external/libselinux/src/android.c + * system/core/logd/LogStatistics.cpp + * system/core/init/ueventd.cpp + * system/core/init/util.cpp + */ struct android_id_info { const char *name; unsigned aid; @@ -191,116 +198,24 @@ struct fs_path_config { const char *prefix; }; -/* Rules for directories. -** These rules are applied based on "first match", so they -** should start with the most specific path and work their -** way up to the root. -*/ - -static const struct fs_path_config android_dirs[] = { - { 00770, AID_SYSTEM, AID_CACHE, 0, "cache" }, - { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" }, - { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" }, - { 00771, AID_ROOT, AID_ROOT, 0, "data/dalvik-cache" }, - { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" }, - { 00771, AID_SHELL, AID_SHELL, 0, "data/local/tmp" }, - { 00771, AID_SHELL, AID_SHELL, 0, "data/local" }, - { 01771, AID_SYSTEM, AID_MISC, 0, "data/misc" }, - { 00770, AID_DHCP, AID_DHCP, 0, "data/misc/dhcp" }, - { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" }, - { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" }, - { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" }, - { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" }, - { 00750, AID_ROOT, AID_SHELL, 0, "sbin" }, - { 00755, AID_ROOT, AID_SHELL, 0, "system/bin" }, - { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" }, - { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin" }, - { 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" }, - { 00755, AID_ROOT, AID_SHELL, 0, "vendor" }, - { 00777, AID_ROOT, AID_ROOT, 0, "sdcard" }, - { 00755, AID_ROOT, AID_ROOT, 0, 0 }, -}; - -/* Rules for files. -** These rules are applied based on "first match", so they -** should start with the most specific path and work their -** way up to the root. Prefixes ending in * denotes wildcard -** and will allow partial matches. -*/ -static const struct fs_path_config android_files[] = { - { 00440, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.rc" }, - { 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.sh" }, - { 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.ril" }, - { 00550, AID_DHCP, AID_SHELL, 0, "system/etc/dhcpcd/dhcpcd-run-hooks" }, - { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" }, - { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" }, - { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" }, - { 00644, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/*" }, - { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" }, - { 00644, AID_APP, AID_APP, 0, "data/data/*" }, - - /* the following five files are INTENTIONALLY set-uid, but they - * are NOT included on user builds. */ - { 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" }, - { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" }, - { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procrank" }, - { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" }, - { 04770, AID_ROOT, AID_RADIO, 0, "system/bin/pppd-ril" }, - - /* the following files have enhanced capabilities and ARE included in user builds. */ - { 00750, AID_ROOT, AID_SHELL, (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" }, - - { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" }, - { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" }, - { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" }, - { 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" }, - { 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" }, - { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" }, - { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor/bin/*" }, - { 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" }, - { 00750, AID_ROOT, AID_SHELL, 0, "sbin/*" }, - { 00755, AID_ROOT, AID_ROOT, 0, "bin/*" }, - { 00750, AID_ROOT, AID_SHELL, 0, "init*" }, - { 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" }, - { 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" }, - { 00644, AID_ROOT, AID_ROOT, 0, 0 }, -}; +/* Rules for directories and files has moved to system/code/libcutils/fs_config.c */ -static inline void fs_config(const char *path, int dir, - unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities) -{ - const struct fs_path_config *pc; - int plen; +__BEGIN_DECLS - if (path[0] == '/') { - path++; - } +/* + * Used in: + * build/tools/fs_config/fs_config.c + * build/tools/fs_get_stats/fs_get_stats.c + * external/genext2fs/genext2fs.c + * external/squashfs-tools/squashfs-tools/android.c + * system/core/cpio/mkbootfs.c + * system/core/adb/file_sync_service.cpp + * system/extras/ext4_utils/canned_fs_config.c + */ +void fs_config(const char *path, int dir, + unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities); - pc = dir ? android_dirs : android_files; - plen = strlen(path); - for(; pc->prefix; pc++){ - int len = strlen(pc->prefix); - if (dir) { - if(plen < len) continue; - if(!strncmp(pc->prefix, path, len)) break; - continue; - } - /* If name ends in * then allow partial matches. */ - if (pc->prefix[len -1] == '*') { - if(!strncmp(pc->prefix, path, len - 1)) break; - } else if (plen == len){ - if(!strncmp(pc->prefix, path, len)) break; - } - } - *uid = pc->uid; - *gid = pc->gid; - *mode = (*mode & (~07777)) | pc->mode; - *capabilities = pc->capabilities; +__END_DECLS -#if 0 - fprintf(stderr,"< '%s' '%s' %d %d %o >\n", - path, pc->prefix ? pc->prefix : "", *uid, *gid, *mode); -#endif -} #endif #endif diff --git a/include/utils/Compat.h b/include/utils/Compat.h index ca4a8e0..7d96310 100644 --- a/include/utils/Compat.h +++ b/include/utils/Compat.h @@ -41,12 +41,12 @@ static inline ssize_t pread64(int fd, void* buf, size_t nbytes, off64_t offset) #define DEFFILEMODE 0666 #endif /* _WIN32 */ -#if HAVE_PRINTF_ZD -# define ZD "%zd" -# define ZD_TYPE ssize_t +#if defined(_WIN32) +#define ZD "%ld" +#define ZD_TYPE long #else -# define ZD "%ld" -# define ZD_TYPE long +#define ZD "%zd" +#define ZD_TYPE ssize_t #endif /* diff --git a/init/Android.mk b/init/Android.mk index 94d3dad..9d91a3f 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -50,7 +50,7 @@ LOCAL_SRC_FILES:= \ watchdogd.cpp \ LOCAL_MODULE:= init - +LOCAL_C_INCLUDES += system/extras/ext4_utils LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) @@ -61,11 +61,14 @@ LOCAL_STATIC_LIBRARIES := \ liblogwrap \ libcutils \ libbase \ + libext4_utils_static \ + libutils \ liblog \ libc \ libselinux \ libmincrypt \ - libext4_utils_static + libc++_static \ + libdl # Create symlinks LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \ diff --git a/init/builtins.cpp b/init/builtins.cpp index aa5c649..3bbaf83 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -29,6 +29,7 @@ #include <sys/wait.h> #include <unistd.h> #include <linux/loop.h> +#include <ext4_crypt.h> #include <selinux/selinux.h> #include <selinux/label.h> @@ -153,68 +154,6 @@ int do_exec(int nargs, char** args) { return 0; } -// TODO: remove execonce when exec is available. -int do_execonce(int nargs, char **args) -{ - pid_t child; - int child_status = 0; - static int already_done; - - if (already_done) { - return -1; - } - already_done = 1; - if (!(child = fork())) { - /* - * Child process. - */ - zap_stdio(); - char *exec_args[100]; - size_t num_process_args = nargs; - - memset(exec_args, 0, sizeof(exec_args)); - if (num_process_args > ARRAY_SIZE(exec_args) - 1) { - ERROR("exec called with %zu args, limit is %zu", num_process_args, - ARRAY_SIZE(exec_args) - 1); - _exit(1); - } - for (size_t i = 1; i < num_process_args; i++) - exec_args[i - 1] = args[i]; - - if (execv(exec_args[0], exec_args) == -1) { - ERROR("Failed to execv '%s' (%s)", exec_args[0], strerror(errno)); - _exit(1); - } - ERROR("Returned from execv()!"); - _exit(1); - } - - /* - * Parent process. - */ - if (child == -1) { - ERROR("Fork failed\n"); - return -1; - } - - if (TEMP_FAILURE_RETRY(waitpid(child, &child_status, 0)) == -1) { - ERROR("waitpid(): failed (%s)\n", strerror(errno)); - return -1; - } - - if (WIFSIGNALED(child_status)) { - INFO("Child exited due to signal %d\n", WTERMSIG(child_status)); - return -1; - } else if (WIFEXITED(child_status)) { - INFO("Child exited normally (exit code %d)\n", WEXITSTATUS(child_status)); - return WEXITSTATUS(child_status); - } - - ERROR("Abnormal child process exit\n"); - - return -1; -} - int do_export(int nargs, char **args) { return add_environment(args[1], args[2]); @@ -302,7 +241,7 @@ int do_mkdir(int nargs, char **args) } } - return 0; + return e4crypt_set_directory_policy(args[1]); } static struct { @@ -446,6 +385,17 @@ static int wipe_data_via_recovery() while (1) { pause(); } // never reached } +/* + * Callback to make a directory from the ext4 code + */ +static int do_mount_alls_make_dir(const char* dir) +{ + if (make_dir(dir, 0700) && errno != EEXIST) { + return -1; + } + + return 0; +} /* * This function might request a reboot, in which case it will @@ -514,6 +464,37 @@ int do_mount_all(int nargs, char **args) ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n"); ret = wipe_data_via_recovery(); /* If reboot worked, there is no return. */ + } else if (ret == FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED) { + // We have to create the key files here. Only init can call make_dir, + // and we can't do it from fs_mgr as then fs_mgr would depend on + // make_dir creating a circular dependency. + fstab = fs_mgr_read_fstab(args[1]); + for (int i = 0; i < fstab->num_entries; ++i) { + if (fs_mgr_is_file_encrypted(&fstab->recs[i])) { + if (e4crypt_create_device_key(fstab->recs[i].mount_point, + do_mount_alls_make_dir)) { + ERROR("Could not create device key on %s" + " - continue unencrypted\n", + fstab->recs[i].mount_point); + } + } + } + fs_mgr_free_fstab(fstab); + + if (e4crypt_install_keyring()) { + return -1; + } + property_set("ro.crypto.state", "encrypted"); + + // Although encrypted, we have device key, so we do not need to + // do anything different from the nonencrypted case. + action_for_each_trigger("nonencrypted", action_add_queue_tail); + } else if (ret == FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED) { + if (e4crypt_install_keyring()) { + return -1; + } + property_set("ro.crypto.state", "encrypted"); + property_set("vold.decrypt", "trigger_restart_min_framework"); } else if (ret > 0) { ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret); } @@ -867,3 +848,12 @@ int do_wait(int nargs, char **args) } else return -1; } + +int do_installkey(int nargs, char **args) +{ + if (nargs == 2) { + return e4crypt_install_key(args[1]); + } + + return -1; +} diff --git a/init/init_parser.cpp b/init/init_parser.cpp index 294dc19..af935d7 100644 --- a/init/init_parser.cpp +++ b/init/init_parser.cpp @@ -122,7 +122,6 @@ static int lookup_keyword(const char *s) break; case 'c': if (!strcmp(s, "opy")) return K_copy; - if (!strcmp(s, "apability")) return K_capability; if (!strcmp(s, "lass")) return K_class; if (!strcmp(s, "lass_start")) return K_class_start; if (!strcmp(s, "lass_stop")) return K_class_stop; @@ -139,7 +138,6 @@ static int lookup_keyword(const char *s) case 'e': if (!strcmp(s, "nable")) return K_enable; if (!strcmp(s, "xec")) return K_exec; - if (!strcmp(s, "xeconce")) return K_execonce; if (!strcmp(s, "xport")) return K_export; break; case 'g': @@ -153,6 +151,7 @@ static int lookup_keyword(const char *s) if (!strcmp(s, "fup")) return K_ifup; if (!strcmp(s, "nsmod")) return K_insmod; if (!strcmp(s, "mport")) return K_import; + if (!strcmp(s, "nstallkey")) return K_installkey; break; case 'k': if (!strcmp(s, "eycodes")) return K_keycodes; @@ -775,8 +774,6 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args kw = lookup_keyword(args[0]); switch (kw) { - case K_capability: - break; case K_class: if (nargs != 2) { parse_error(state, "class option requires a classname\n"); diff --git a/init/keywords.h b/init/keywords.h index 09f645b..059dde1 100644 --- a/init/keywords.h +++ b/init/keywords.h @@ -6,11 +6,11 @@ int do_class_reset(int nargs, char **args); int do_domainname(int nargs, char **args); int do_enable(int nargs, char **args); int do_exec(int nargs, char **args); -int do_execonce(int nargs, char **args); int do_export(int nargs, char **args); int do_hostname(int nargs, char **args); int do_ifup(int nargs, char **args); int do_insmod(int nargs, char **args); +int do_installkey(int nargs, char **args); int do_mkdir(int nargs, char **args); int do_mount_all(int nargs, char **args); int do_mount(int nargs, char **args); @@ -44,7 +44,6 @@ int do_wait(int nargs, char **args); enum { K_UNKNOWN, #endif - KEYWORD(capability, OPTION, 0, 0) KEYWORD(class, OPTION, 0, 0) KEYWORD(class_start, COMMAND, 1, do_class_start) KEYWORD(class_stop, COMMAND, 1, do_class_stop) @@ -55,12 +54,12 @@ enum { KEYWORD(domainname, COMMAND, 1, do_domainname) KEYWORD(enable, COMMAND, 1, do_enable) KEYWORD(exec, COMMAND, 1, do_exec) - KEYWORD(execonce, COMMAND, 1, do_execonce) KEYWORD(export, COMMAND, 2, do_export) KEYWORD(group, OPTION, 0, 0) KEYWORD(hostname, COMMAND, 1, do_hostname) KEYWORD(ifup, COMMAND, 1, do_ifup) KEYWORD(insmod, COMMAND, 1, do_insmod) + KEYWORD(installkey, COMMAND, 1, do_installkey) KEYWORD(import, SECTION, 1, 0) KEYWORD(keycodes, OPTION, 0, 0) KEYWORD(mkdir, COMMAND, 1, do_mkdir) diff --git a/init/readme.txt b/init/readme.txt index 630dd03..84afd11 100644 --- a/init/readme.txt +++ b/init/readme.txt @@ -182,10 +182,6 @@ exec [ <seclabel> [ <user> [ <group> ]* ] ] -- <command> [ <argument> ]* groups can be provided. No other commands will be run until this one finishes. -execonce <path> [ <argument> ]* - Use exec instead. This command will be removed after existing callers have - moved to exec. - export <name> <value> Set the environment variable <name> equal to <value> in the global environment (which will be inherited by all processes diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk index d7eaa68..35fed6d 100644 --- a/libbacktrace/Android.build.mk +++ b/libbacktrace/Android.build.mk @@ -19,28 +19,37 @@ include $(CLEAR_VARS) LOCAL_MODULE := $(module) LOCAL_MODULE_TAGS := $(module_tag) LOCAL_MULTILIB := $($(module)_multilib) +ifeq ($(LOCAL_MULTILIB),both) +ifneq ($(build_target),$(filter $(build_target),SHARED_LIBRARY STATIC_LIBRRARY)) + LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 + LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 +endif +endif LOCAL_ADDITIONAL_DEPENDENCIES := \ $(LOCAL_PATH)/Android.mk \ $(LOCAL_PATH)/Android.build.mk \ LOCAL_CFLAGS := \ - $(common_cflags) \ + $(libbacktrace_common_cflags) \ $($(module)_cflags) \ $($(module)_cflags_$(build_type)) \ +LOCAL_CLANG_CFLAGS += \ + $(libbacktrace_common_clang_cflags) \ + LOCAL_CONLYFLAGS += \ - $(common_conlyflags) \ + $(libbacktrace_common_conlyflags) \ $($(module)_conlyflags) \ $($(module)_conlyflags_$(build_type)) \ LOCAL_CPPFLAGS += \ - $(common_cppflags) \ + $(libbacktrace_common_cppflags) \ $($(module)_cppflags) \ $($(module)_cppflags_$(build_type)) \ LOCAL_C_INCLUDES := \ - $(common_c_includes) \ + $(libbacktrace_common_c_includes) \ $($(module)_c_includes) \ $($(module)_c_includes_$(build_type)) \ diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk index f3b28dd..b875efd 100755..100644 --- a/libbacktrace/Android.mk +++ b/libbacktrace/Android.mk @@ -16,16 +16,20 @@ LOCAL_PATH:= $(call my-dir) -common_cflags := \ +libbacktrace_common_cflags := \ -Wall \ -Werror \ -common_conlyflags := \ +libbacktrace_common_conlyflags := \ -std=gnu99 \ -common_cppflags := \ +libbacktrace_common_cppflags := \ -std=gnu++11 \ +# The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists. +libbacktrace_common_clang_cflags += \ + -Wno-inline-asm + build_host := false ifeq ($(HOST_OS),linux) ifeq ($(HOST_ARCH),$(filter $(HOST_ARCH),x86 x86_64)) @@ -37,20 +41,21 @@ endif # The libbacktrace library. #------------------------------------------------------------------------- libbacktrace_src_files := \ - BacktraceImpl.cpp \ + Backtrace.cpp \ + BacktraceCurrent.cpp \ BacktraceMap.cpp \ - BacktraceThread.cpp \ + BacktracePtrace.cpp \ thread_utils.c \ - -libbacktrace_shared_libraries_target := \ - libcutils \ - -libbacktrace_src_files += \ + ThreadEntry.cpp \ UnwindCurrent.cpp \ UnwindMap.cpp \ UnwindPtrace.cpp \ +libbacktrace_shared_libraries_target := \ + libcutils \ + libbacktrace_shared_libraries := \ + libbase \ libunwind \ libunwind-ptrace \ @@ -86,6 +91,7 @@ module := libbacktrace_test module_tag := debug build_type := target build_target := SHARED_LIBRARY +libbacktrace_test_multilib := both include $(LOCAL_PATH)/Android.build.mk build_type := host include $(LOCAL_PATH)/Android.build.mk @@ -124,6 +130,7 @@ module := backtrace_test module_tag := debug build_type := target build_target := NATIVE_TEST +backtrace_test_multilib := both include $(LOCAL_PATH)/Android.build.mk build_type := host include $(LOCAL_PATH)/Android.build.mk diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp new file mode 100644 index 0000000..91ca8b7 --- /dev/null +++ b/libbacktrace/Backtrace.cpp @@ -0,0 +1,138 @@ +/* + * 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. + */ + +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/types.h> +#include <ucontext.h> + +#include <string> + +#include <base/stringprintf.h> + +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> + +#include "BacktraceLog.h" +#include "thread_utils.h" +#include "UnwindCurrent.h" +#include "UnwindPtrace.h" + +using android::base::StringPrintf; + +//------------------------------------------------------------------------- +// Backtrace functions. +//------------------------------------------------------------------------- +Backtrace::Backtrace(pid_t pid, pid_t tid, BacktraceMap* map) + : pid_(pid), tid_(tid), map_(map), map_shared_(true) { + if (map_ == nullptr) { + map_ = BacktraceMap::Create(pid); + map_shared_ = false; + } +} + +Backtrace::~Backtrace() { + if (map_ && !map_shared_) { + delete map_; + map_ = nullptr; + } +} + +extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len, + int* status); + +std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) { + std::string func_name = GetFunctionNameRaw(pc, offset); + if (!func_name.empty()) { +#if defined(__APPLE__) + // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7. + if (func_name[0] != '_') { + return func_name; + } +#endif + char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0); + if (name) { + func_name = name; + free(name); + } + } + return func_name; +} + +bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) { + if (ptr & (sizeof(word_t)-1)) { + BACK_LOGW("invalid pointer %p", reinterpret_cast<void*>(ptr)); + *out_value = static_cast<word_t>(-1); + return false; + } + return true; +} + +std::string Backtrace::FormatFrameData(size_t frame_num) { + if (frame_num >= frames_.size()) { + return ""; + } + return FormatFrameData(&frames_[frame_num]); +} + +std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) { + const char* map_name; + if (BacktraceMap::IsValid(frame->map) && !frame->map.name.empty()) { + map_name = frame->map.name.c_str(); + } else { + map_name = "<unknown>"; + } + + uintptr_t relative_pc; + if (BacktraceMap::IsValid(frame->map)) { + relative_pc = frame->pc - frame->map.start; + } else { + relative_pc = frame->pc; + } + + std::string line(StringPrintf("#%02zu pc %" PRIPTR " %s", frame->num, relative_pc, map_name)); + if (!frame->func_name.empty()) { + line += " (" + frame->func_name; + if (frame->func_offset) { + line += StringPrintf("+%" PRIuPTR, frame->func_offset); + } + line += ')'; + } + + return line; +} + +void Backtrace::FillInMap(uintptr_t pc, backtrace_map_t* map) { + map_->FillIn(pc, map); +} + +Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) { + if (pid == BACKTRACE_CURRENT_PROCESS) { + pid = getpid(); + if (tid == BACKTRACE_CURRENT_THREAD) { + tid = gettid(); + } + } else if (tid == BACKTRACE_CURRENT_THREAD) { + tid = pid; + } + + if (pid == getpid()) { + return new UnwindCurrent(pid, tid, map); + } else { + return new UnwindPtrace(pid, tid, map); + } +} diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp new file mode 100644 index 0000000..fd1f4da --- /dev/null +++ b/libbacktrace/BacktraceCurrent.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 _GNU_SOURCE 1 +#include <errno.h> +#include <stdint.h> +#include <string.h> +#include <sys/param.h> +#include <sys/ptrace.h> +#include <sys/types.h> +#include <ucontext.h> +#include <unistd.h> + +#include <string> + +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> + +#include "BacktraceCurrent.h" +#include "BacktraceLog.h" +#include "ThreadEntry.h" +#include "thread_utils.h" + +bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) { + if (!VerifyReadWordArgs(ptr, out_value)) { + return false; + } + + backtrace_map_t map; + FillInMap(ptr, &map); + if (BacktraceMap::IsValid(map) && map.flags & PROT_READ) { + *out_value = *reinterpret_cast<word_t*>(ptr); + return true; + } else { + BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr)); + *out_value = static_cast<word_t>(-1); + return false; + } +} + +size_t BacktraceCurrent::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) { + backtrace_map_t map; + FillInMap(addr, &map); + if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) { + return 0; + } + bytes = MIN(map.end - addr, bytes); + memcpy(buffer, reinterpret_cast<uint8_t*>(addr), bytes); + return bytes; +} + +bool BacktraceCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { + if (ucontext) { + return UnwindFromContext(num_ignore_frames, ucontext); + } + + if (Tid() != gettid()) { + return UnwindThread(num_ignore_frames); + } + + return UnwindFromContext(num_ignore_frames, nullptr); +} + +bool BacktraceCurrent::DiscardFrame(const backtrace_frame_data_t& frame) { + if (BacktraceMap::IsValid(frame.map)) { + const std::string library = basename(frame.map.name.c_str()); + if (library == "libunwind.so" || library == "libbacktrace.so") { + return true; + } + } + return false; +} + +static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER; + +static void SignalHandler(int, siginfo_t*, void* sigcontext) { + ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false); + if (!entry) { + BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid()); + return; + } + + entry->CopyUcontextFromSigcontext(sigcontext); + + // Indicate the ucontext is now valid. + entry->Wake(); + + // Pause the thread until the unwind is complete. This avoids having + // the thread run ahead causing problems. + // The number indicates that we are waiting for the second Wake() call + // overall which is made by the thread requesting an unwind. + entry->Wait(2); + + ThreadEntry::Remove(entry); +} + +bool BacktraceCurrent::UnwindThread(size_t num_ignore_frames) { + // Prevent multiple threads trying to set the trigger action on different + // threads at the same time. + pthread_mutex_lock(&g_sigaction_mutex); + + ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid()); + entry->Lock(); + + struct sigaction act, oldact; + memset(&act, 0, sizeof(act)); + act.sa_sigaction = SignalHandler; + act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; + sigemptyset(&act.sa_mask); + if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) { + BACK_LOGW("sigaction failed %s", strerror(errno)); + entry->Unlock(); + ThreadEntry::Remove(entry); + pthread_mutex_unlock(&g_sigaction_mutex); + return false; + } + + if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) { + BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno)); + sigaction(THREAD_SIGNAL, &oldact, nullptr); + entry->Unlock(); + ThreadEntry::Remove(entry); + pthread_mutex_unlock(&g_sigaction_mutex); + return false; + } + + // Wait for the thread to get the ucontext. The number indicates + // that we are waiting for the first Wake() call made by the thread. + entry->Wait(1); + + // After the thread has received the signal, allow other unwinders to + // continue. + sigaction(THREAD_SIGNAL, &oldact, nullptr); + pthread_mutex_unlock(&g_sigaction_mutex); + + bool unwind_done = UnwindFromContext(num_ignore_frames, entry->GetUcontext()); + + // Tell the signal handler to exit and release the entry. + entry->Wake(); + + return unwind_done; +} diff --git a/libbacktrace/BacktraceCurrent.h b/libbacktrace/BacktraceCurrent.h new file mode 100644 index 0000000..8aad36d --- /dev/null +++ b/libbacktrace/BacktraceCurrent.h @@ -0,0 +1,58 @@ +/* + * 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 _LIBBACKTRACE_BACKTRACE_CURRENT_H +#define _LIBBACKTRACE_BACKTRACE_CURRENT_H + +#include <stdint.h> +#include <sys/types.h> +#include <ucontext.h> + +#include <backtrace/Backtrace.h> + +// The signal used to cause a thread to dump the stack. +#if defined(__GLIBC__) +// In order to run the backtrace_tests on the host, we can't use +// the internal real time signals used by GLIBC. To avoid this, +// use SIGRTMIN for the signal to dump the stack. +#define THREAD_SIGNAL SIGRTMIN +#else +#define THREAD_SIGNAL (__SIGRTMIN+1) +#endif + +class BacktraceMap; + +class BacktraceCurrent : public Backtrace { +public: + BacktraceCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {} + virtual ~BacktraceCurrent() {} + + size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override; + + bool ReadWord(uintptr_t ptr, word_t* out_value) override; + + bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override; + +protected: + bool DiscardFrame(const backtrace_frame_data_t& frame); + +private: + bool UnwindThread(size_t num_ignore_frames); + + virtual bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) = 0; +}; + +#endif // _LIBBACKTRACE_BACKTRACE_CURRENT_H diff --git a/libbacktrace/BacktraceImpl.cpp b/libbacktrace/BacktraceImpl.cpp deleted file mode 100644 index 4650b6a..0000000 --- a/libbacktrace/BacktraceImpl.cpp +++ /dev/null @@ -1,283 +0,0 @@ -/* - * 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. - */ - -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <sys/param.h> -#include <sys/ptrace.h> -#include <sys/types.h> -#include <ucontext.h> -#include <unistd.h> - -#include <string> - -#include <backtrace/Backtrace.h> -#include <backtrace/BacktraceMap.h> - -#include "BacktraceImpl.h" -#include "BacktraceLog.h" -#include "thread_utils.h" - -//------------------------------------------------------------------------- -// Backtrace functions. -//------------------------------------------------------------------------- -Backtrace::Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map) - : pid_(pid), tid_(-1), map_(map), map_shared_(true), impl_(impl) { - impl_->SetParent(this); - - if (map_ == NULL) { - map_ = BacktraceMap::Create(pid); - map_shared_ = false; - } -} - -Backtrace::~Backtrace() { - if (impl_) { - delete impl_; - impl_ = NULL; - } - - if (map_ && !map_shared_) { - delete map_; - map_ = NULL; - } -} - -bool Backtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { - return impl_->Unwind(num_ignore_frames, ucontext); -} - -extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len, - int* status); - -std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) { - std::string func_name = impl_->GetFunctionNameRaw(pc, offset); - if (!func_name.empty()) { -#if defined(__APPLE__) - // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7. - if (func_name[0] != '_') { - return func_name; - } -#endif - char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0); - if (name) { - func_name = name; - free(name); - } - } - return func_name; -} - -bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) { - if (ptr & (sizeof(word_t)-1)) { - BACK_LOGW("invalid pointer %p", (void*)ptr); - *out_value = (word_t)-1; - return false; - } - return true; -} - -std::string Backtrace::FormatFrameData(size_t frame_num) { - if (frame_num >= frames_.size()) { - return ""; - } - return FormatFrameData(&frames_[frame_num]); -} - -std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) { - const char* map_name; - if (BacktraceMap::IsValid(frame->map) && !frame->map.name.empty()) { - map_name = frame->map.name.c_str(); - } else { - map_name = "<unknown>"; - } - - uintptr_t relative_pc; - if (BacktraceMap::IsValid(frame->map)) { - relative_pc = frame->pc - frame->map.start; - } else { - relative_pc = frame->pc; - } - - char buf[512]; - if (!frame->func_name.empty() && frame->func_offset) { - snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s+%" PRIuPTR ")", - frame->num, (int)sizeof(uintptr_t)*2, relative_pc, map_name, - frame->func_name.c_str(), frame->func_offset); - } else if (!frame->func_name.empty()) { - snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s)", frame->num, - (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name.c_str()); - } else { - snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s", frame->num, - (int)sizeof(uintptr_t)*2, relative_pc, map_name); - } - - return buf; -} - -void Backtrace::FillInMap(uintptr_t pc, backtrace_map_t* map) { - map_->FillIn(pc, map); -} - -//------------------------------------------------------------------------- -// BacktraceCurrent functions. -//------------------------------------------------------------------------- -BacktraceCurrent::BacktraceCurrent( - BacktraceImpl* impl, BacktraceMap* map) : Backtrace(impl, getpid(), map) { -} - -BacktraceCurrent::~BacktraceCurrent() { -} - -bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) { - if (!VerifyReadWordArgs(ptr, out_value)) { - return false; - } - - backtrace_map_t map; - FillInMap(ptr, &map); - if (BacktraceMap::IsValid(map) && map.flags & PROT_READ) { - *out_value = *reinterpret_cast<word_t*>(ptr); - return true; - } else { - BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr)); - *out_value = static_cast<word_t>(-1); - return false; - } -} - -size_t BacktraceCurrent::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) { - backtrace_map_t map; - FillInMap(addr, &map); - if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) { - return 0; - } - bytes = MIN(map.end - addr, bytes); - memcpy(buffer, reinterpret_cast<uint8_t*>(addr), bytes); - return bytes; -} - -//------------------------------------------------------------------------- -// BacktracePtrace functions. -//------------------------------------------------------------------------- -BacktracePtrace::BacktracePtrace( - BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map) - : Backtrace(impl, pid, map) { - tid_ = tid; -} - -BacktracePtrace::~BacktracePtrace() { -} - -#if !defined(__APPLE__) -static bool PtraceRead(pid_t tid, uintptr_t addr, word_t* out_value) { - // ptrace() returns -1 and sets errno when the operation fails. - // To disambiguate -1 from a valid result, we clear errno beforehand. - errno = 0; - *out_value = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr), NULL); - if (*out_value == static_cast<word_t>(-1) && errno) { - BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s", - reinterpret_cast<void*>(addr), tid, strerror(errno)); - return false; - } - return true; -} -#endif - -bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) { -#if defined(__APPLE__) - BACK_LOGW("MacOS does not support reading from another pid."); - return false; -#else - if (!VerifyReadWordArgs(ptr, out_value)) { - return false; - } - - backtrace_map_t map; - FillInMap(ptr, &map); - if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) { - return false; - } - - return PtraceRead(Tid(), ptr, out_value); -#endif -} - -size_t BacktracePtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) { -#if defined(__APPLE__) - BACK_LOGW("MacOS does not support reading from another pid."); - return 0; -#else - backtrace_map_t map; - FillInMap(addr, &map); - if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) { - return 0; - } - - bytes = MIN(map.end - addr, bytes); - size_t bytes_read = 0; - word_t data_word; - size_t align_bytes = addr & (sizeof(word_t) - 1); - if (align_bytes != 0) { - if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) { - return 0; - } - align_bytes = sizeof(word_t) - align_bytes; - memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + sizeof(word_t) - align_bytes, - align_bytes); - addr += align_bytes; - buffer += align_bytes; - bytes -= align_bytes; - bytes_read += align_bytes; - } - - size_t num_words = bytes / sizeof(word_t); - for (size_t i = 0; i < num_words; i++) { - if (!PtraceRead(Tid(), addr, &data_word)) { - return bytes_read; - } - memcpy(buffer, &data_word, sizeof(word_t)); - buffer += sizeof(word_t); - addr += sizeof(word_t); - bytes_read += sizeof(word_t); - } - - size_t left_over = bytes & (sizeof(word_t) - 1); - if (left_over) { - if (!PtraceRead(Tid(), addr, &data_word)) { - return bytes_read; - } - memcpy(buffer, &data_word, left_over); - bytes_read += left_over; - } - return bytes_read; -#endif -} - -Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) { - if (pid == BACKTRACE_CURRENT_PROCESS || pid == getpid()) { - if (tid == BACKTRACE_CURRENT_THREAD || tid == gettid()) { - return CreateCurrentObj(map); - } else { - return CreateThreadObj(tid, map); - } - } else if (tid == BACKTRACE_CURRENT_THREAD) { - return CreatePtraceObj(pid, pid, map); - } else { - return CreatePtraceObj(pid, tid, map); - } -} diff --git a/libbacktrace/BacktraceImpl.h b/libbacktrace/BacktraceImpl.h deleted file mode 100755 index 18c3cb5..0000000 --- a/libbacktrace/BacktraceImpl.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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 _LIBBACKTRACE_BACKTRACE_IMPL_H -#define _LIBBACKTRACE_BACKTRACE_IMPL_H - -#include <backtrace/Backtrace.h> -#include <backtrace/BacktraceMap.h> - -#include <sys/types.h> - -class BacktraceImpl { -public: - virtual ~BacktraceImpl() { } - - virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) = 0; - - // The name returned is not demangled, Backtrace::GetFunctionName() - // takes care of demangling the name. - virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0; - - void SetParent(Backtrace* backtrace) { backtrace_obj_ = backtrace; } - - inline pid_t Pid() { return backtrace_obj_->Pid(); } - inline pid_t Tid() { return backtrace_obj_->Tid(); } - - inline void FillInMap(uintptr_t addr, backtrace_map_t* map) { - backtrace_obj_->FillInMap(addr, map); - } - inline std::string GetFunctionName(uintptr_t pc, uintptr_t* offset) { - return backtrace_obj_->GetFunctionName(pc, offset); - } - inline BacktraceMap* GetMap() { return backtrace_obj_->GetMap(); } - -protected: - inline std::vector<backtrace_frame_data_t>* GetFrames() { return &backtrace_obj_->frames_; } - - Backtrace* backtrace_obj_; -}; - -class BacktraceCurrent : public Backtrace { -public: - BacktraceCurrent(BacktraceImpl* impl, BacktraceMap* map); - virtual ~BacktraceCurrent(); - - size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes); - - bool ReadWord(uintptr_t ptr, word_t* out_value); -}; - -class BacktracePtrace : public Backtrace { -public: - BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map); - virtual ~BacktracePtrace(); - - size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes); - - bool ReadWord(uintptr_t ptr, word_t* out_value); -}; - -Backtrace* CreateCurrentObj(BacktraceMap* map); -Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map); -Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map); - -#endif // _LIBBACKTRACE_BACKTRACE_IMPL_H diff --git a/libbacktrace/BacktraceLog.h b/libbacktrace/BacktraceLog.h index 1632ec2..1632ec2 100755..100644 --- a/libbacktrace/BacktraceLog.h +++ b/libbacktrace/BacktraceLog.h diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp index 82a4085..b0ada46 100644 --- a/libbacktrace/BacktraceMap.cpp +++ b/libbacktrace/BacktraceMap.cpp @@ -15,18 +15,15 @@ */ #include <ctype.h> +#include <stdint.h> #include <sys/types.h> #include <unistd.h> -#include <string> -#include <vector> - #include <backtrace/backtrace_constants.h> #include <backtrace/BacktraceMap.h> #include <log/log.h> #include "thread_utils.h" -#include "BacktraceImpl.h" BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) { if (pid_ < 0) { @@ -116,7 +113,7 @@ bool BacktraceMap::Build() { snprintf(path, sizeof(path), "/proc/%d/maps", pid_); FILE* fp = fopen(path, "r"); #endif - if (fp == NULL) { + if (fp == nullptr) { return false; } @@ -142,7 +139,7 @@ BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) { BacktraceMap* map = new BacktraceMap(pid); if (!map->Build()) { delete map; - return NULL; + return nullptr; } return map; } diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp new file mode 100644 index 0000000..6134438 --- /dev/null +++ b/libbacktrace/BacktracePtrace.cpp @@ -0,0 +1,116 @@ +/* + * 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. + */ + +#include <errno.h> +#include <stdint.h> +#include <string.h> +#include <sys/param.h> +#include <sys/ptrace.h> +#include <sys/types.h> +#include <ucontext.h> +#include <unistd.h> + +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> + +#include "BacktraceLog.h" +#include "BacktracePtrace.h" +#include "thread_utils.h" + +#if !defined(__APPLE__) +static bool PtraceRead(pid_t tid, uintptr_t addr, word_t* out_value) { + // ptrace() returns -1 and sets errno when the operation fails. + // To disambiguate -1 from a valid result, we clear errno beforehand. + errno = 0; + *out_value = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr), nullptr); + if (*out_value == static_cast<word_t>(-1) && errno) { + BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s", + reinterpret_cast<void*>(addr), tid, strerror(errno)); + return false; + } + return true; +} +#endif + +bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) { +#if defined(__APPLE__) + BACK_LOGW("MacOS does not support reading from another pid."); + return false; +#else + if (!VerifyReadWordArgs(ptr, out_value)) { + return false; + } + + backtrace_map_t map; + FillInMap(ptr, &map); + if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) { + return false; + } + + return PtraceRead(Tid(), ptr, out_value); +#endif +} + +size_t BacktracePtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) { +#if defined(__APPLE__) + BACK_LOGW("MacOS does not support reading from another pid."); + return 0; +#else + backtrace_map_t map; + FillInMap(addr, &map); + if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) { + return 0; + } + + bytes = MIN(map.end - addr, bytes); + size_t bytes_read = 0; + word_t data_word; + size_t align_bytes = addr & (sizeof(word_t) - 1); + if (align_bytes != 0) { + if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) { + return 0; + } + align_bytes = sizeof(word_t) - align_bytes; + memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + sizeof(word_t) - align_bytes, + align_bytes); + addr += align_bytes; + buffer += align_bytes; + bytes -= align_bytes; + bytes_read += align_bytes; + } + + size_t num_words = bytes / sizeof(word_t); + for (size_t i = 0; i < num_words; i++) { + if (!PtraceRead(Tid(), addr, &data_word)) { + return bytes_read; + } + memcpy(buffer, &data_word, sizeof(word_t)); + buffer += sizeof(word_t); + addr += sizeof(word_t); + bytes_read += sizeof(word_t); + } + + size_t left_over = bytes & (sizeof(word_t) - 1); + if (left_over) { + if (!PtraceRead(Tid(), addr, &data_word)) { + return bytes_read; + } + memcpy(buffer, &data_word, left_over); + bytes_read += left_over; + } + return bytes_read; +#endif +} diff --git a/libcutils/arch-mips/android_memset.c b/libbacktrace/BacktracePtrace.h index bbc99fe..1d49811 100644 --- a/libcutils/arch-mips/android_memset.c +++ b/libbacktrace/BacktracePtrace.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * 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. @@ -14,18 +14,24 @@ * limitations under the License. */ -#include <cutils/memory.h> +#ifndef _LIBBACKTRACE_BACKTRACE_PTRACE_H +#define _LIBBACKTRACE_BACKTRACE_PTRACE_H -/* Use mips-assembler versions supplied by bionic/libc/arch-mips/string/memset.S: */ -void _memset16(uint16_t* dst, uint16_t value, size_t size); -void _memset32(uint32_t* dst, uint32_t value, size_t size); +#include <stdint.h> +#include <sys/types.h> -void android_memset16(uint16_t* dst, uint16_t value, size_t size) -{ - _memset16(dst, value, size); -} +#include <backtrace/Backtrace.h> -void android_memset32(uint32_t* dst, uint32_t value, size_t size) -{ - _memset32(dst, value, size); -} +class BacktraceMap; + +class BacktracePtrace : public Backtrace { +public: + BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {} + virtual ~BacktracePtrace() {} + + size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes); + + bool ReadWord(uintptr_t ptr, word_t* out_value); +}; + +#endif // _LIBBACKTRACE_BACKTRACE_PTRACE_H diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp deleted file mode 100644 index 439cc3b..0000000 --- a/libbacktrace/BacktraceThread.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * 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. - */ - -#include <errno.h> -#include <inttypes.h> -#include <limits.h> -#include <pthread.h> -#include <signal.h> -#include <stdlib.h> -#include <string.h> -#include <sys/syscall.h> -#include <sys/time.h> -#include <sys/types.h> -#include <ucontext.h> -#include <unistd.h> - -#include <cutils/atomic.h> - -#include "BacktraceLog.h" -#include "BacktraceThread.h" -#include "thread_utils.h" - -//------------------------------------------------------------------------- -// ThreadEntry implementation. -//------------------------------------------------------------------------- -ThreadEntry* ThreadEntry::list_ = NULL; -pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER; - -// Assumes that ThreadEntry::list_mutex_ has already been locked before -// creating a ThreadEntry object. -ThreadEntry::ThreadEntry(pid_t pid, pid_t tid) - : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), - wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0), - next_(ThreadEntry::list_), prev_(NULL) { - pthread_condattr_t attr; - pthread_condattr_init(&attr); - pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); - pthread_cond_init(&wait_cond_, &attr); - - // Add ourselves to the list. - if (ThreadEntry::list_) { - ThreadEntry::list_->prev_ = this; - } - ThreadEntry::list_ = this; -} - -ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) { - pthread_mutex_lock(&ThreadEntry::list_mutex_); - ThreadEntry* entry = list_; - while (entry != NULL) { - if (entry->Match(pid, tid)) { - break; - } - entry = entry->next_; - } - - if (!entry) { - if (create) { - entry = new ThreadEntry(pid, tid); - } - } else { - entry->ref_count_++; - } - pthread_mutex_unlock(&ThreadEntry::list_mutex_); - - return entry; -} - -void ThreadEntry::Remove(ThreadEntry* entry) { - pthread_mutex_unlock(&entry->mutex_); - - pthread_mutex_lock(&ThreadEntry::list_mutex_); - if (--entry->ref_count_ == 0) { - delete entry; - } - pthread_mutex_unlock(&ThreadEntry::list_mutex_); -} - -// Assumes that ThreadEntry::list_mutex_ has already been locked before -// deleting a ThreadEntry object. -ThreadEntry::~ThreadEntry() { - if (list_ == this) { - list_ = next_; - } else { - if (next_) { - next_->prev_ = prev_; - } - prev_->next_ = next_; - } - - next_ = NULL; - prev_ = NULL; - - pthread_cond_destroy(&wait_cond_); -} - -void ThreadEntry::Wait(int value) { - timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) { - BACK_LOGW("clock_gettime failed: %s", strerror(errno)); - abort(); - } - ts.tv_sec += 10; - - pthread_mutex_lock(&wait_mutex_); - while (wait_value_ != value) { - int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts); - if (ret != 0) { - BACK_LOGW("pthread_cond_timedwait failed: %s", strerror(ret)); - break; - } - } - pthread_mutex_unlock(&wait_mutex_); -} - -void ThreadEntry::Wake() { - pthread_mutex_lock(&wait_mutex_); - wait_value_++; - pthread_mutex_unlock(&wait_mutex_); - - pthread_cond_signal(&wait_cond_); -} - -void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) { - ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext); - // The only thing the unwinder cares about is the mcontext data. - memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext)); -} - -//------------------------------------------------------------------------- -// BacktraceThread functions. -//------------------------------------------------------------------------- -static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void SignalHandler(int, siginfo_t*, void* sigcontext) { - ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false); - if (!entry) { - BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid()); - return; - } - - entry->CopyUcontextFromSigcontext(sigcontext); - - // Indicate the ucontext is now valid. - entry->Wake(); - - // Pause the thread until the unwind is complete. This avoids having - // the thread run ahead causing problems. - entry->Wait(2); - - ThreadEntry::Remove(entry); -} - -BacktraceThread::BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map) - : BacktraceCurrent(impl, map) { - tid_ = tid; -} - -BacktraceThread::~BacktraceThread() { -} - -bool BacktraceThread::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { - if (ucontext) { - // Unwind using an already existing ucontext. - return impl_->Unwind(num_ignore_frames, ucontext); - } - - // Prevent multiple threads trying to set the trigger action on different - // threads at the same time. - if (pthread_mutex_lock(&g_sigaction_mutex) < 0) { - BACK_LOGW("sigaction failed: %s", strerror(errno)); - return false; - } - - ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid()); - entry->Lock(); - - struct sigaction act, oldact; - memset(&act, 0, sizeof(act)); - act.sa_sigaction = SignalHandler; - act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; - sigemptyset(&act.sa_mask); - if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) { - BACK_LOGW("sigaction failed %s", strerror(errno)); - entry->Unlock(); - ThreadEntry::Remove(entry); - pthread_mutex_unlock(&g_sigaction_mutex); - return false; - } - - if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) { - BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno)); - sigaction(THREAD_SIGNAL, &oldact, NULL); - entry->Unlock(); - ThreadEntry::Remove(entry); - pthread_mutex_unlock(&g_sigaction_mutex); - return false; - } - - // Wait for the thread to get the ucontext. - entry->Wait(1); - - // After the thread has received the signal, allow other unwinders to - // continue. - sigaction(THREAD_SIGNAL, &oldact, NULL); - pthread_mutex_unlock(&g_sigaction_mutex); - - bool unwind_done = impl_->Unwind(num_ignore_frames, entry->GetUcontext()); - - // Tell the signal handler to exit and release the entry. - entry->Wake(); - - return unwind_done; -} diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp index 442383b..09a721d 100644 --- a/libbacktrace/GetPss.cpp +++ b/libbacktrace/GetPss.cpp @@ -14,11 +14,10 @@ * limitations under the License. */ -#include <assert.h> #include <inttypes.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> -#include <stdint.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> @@ -46,13 +45,22 @@ static bool ReadData(int fd, unsigned long place, uint64_t *data) { size_t GetPssBytes() { FILE* maps = fopen("/proc/self/maps", "r"); - assert(maps != NULL); + if (maps == nullptr) { + return 0; + } int pagecount_fd = open("/proc/kpagecount", O_RDONLY); - assert(pagecount_fd >= 0); + if (pagecount_fd == -1) { + fclose(maps); + return 0; + } int pagemap_fd = open("/proc/self/pagemap", O_RDONLY); - assert(pagemap_fd >= 0); + if (pagemap_fd == -1) { + fclose(maps); + close(pagecount_fd); + return 0; + } char line[4096]; size_t total_pss = 0; diff --git a/libbacktrace/ThreadEntry.cpp b/libbacktrace/ThreadEntry.cpp new file mode 100644 index 0000000..e8b60c8 --- /dev/null +++ b/libbacktrace/ThreadEntry.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2015 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. + */ + +#include <pthread.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> +#include <time.h> +#include <ucontext.h> + +#include "BacktraceLog.h" +#include "ThreadEntry.h" + +// Initialize static member variables. +ThreadEntry* ThreadEntry::list_ = nullptr; +pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER; + +// Assumes that ThreadEntry::list_mutex_ has already been locked before +// creating a ThreadEntry object. +ThreadEntry::ThreadEntry(pid_t pid, pid_t tid) + : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), + wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0), + next_(ThreadEntry::list_), prev_(nullptr) { + pthread_condattr_t attr; + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + pthread_cond_init(&wait_cond_, &attr); + + // Add ourselves to the list. + if (ThreadEntry::list_) { + ThreadEntry::list_->prev_ = this; + } + ThreadEntry::list_ = this; +} + +ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) { + pthread_mutex_lock(&ThreadEntry::list_mutex_); + ThreadEntry* entry = list_; + while (entry != nullptr) { + if (entry->Match(pid, tid)) { + break; + } + entry = entry->next_; + } + + if (!entry) { + if (create) { + entry = new ThreadEntry(pid, tid); + } + } else { + entry->ref_count_++; + } + pthread_mutex_unlock(&ThreadEntry::list_mutex_); + + return entry; +} + +void ThreadEntry::Remove(ThreadEntry* entry) { + pthread_mutex_unlock(&entry->mutex_); + + pthread_mutex_lock(&ThreadEntry::list_mutex_); + if (--entry->ref_count_ == 0) { + delete entry; + } + pthread_mutex_unlock(&ThreadEntry::list_mutex_); +} + +// Assumes that ThreadEntry::list_mutex_ has already been locked before +// deleting a ThreadEntry object. +ThreadEntry::~ThreadEntry() { + if (list_ == this) { + list_ = next_; + } else { + if (next_) { + next_->prev_ = prev_; + } + prev_->next_ = next_; + } + + next_ = nullptr; + prev_ = nullptr; + + pthread_cond_destroy(&wait_cond_); +} + +void ThreadEntry::Wait(int value) { + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec += 10; + + pthread_mutex_lock(&wait_mutex_); + while (wait_value_ != value) { + int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts); + if (ret != 0) { + BACK_LOGW("pthread_cond_timedwait failed: %s", strerror(ret)); + break; + } + } + pthread_mutex_unlock(&wait_mutex_); +} + +void ThreadEntry::Wake() { + pthread_mutex_lock(&wait_mutex_); + wait_value_++; + pthread_mutex_unlock(&wait_mutex_); + + pthread_cond_signal(&wait_cond_); +} + +void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) { + ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext); + // The only thing the unwinder cares about is the mcontext data. + memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext)); +} diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/ThreadEntry.h index 99a8638..94becf2 100644 --- a/libbacktrace/BacktraceThread.h +++ b/libbacktrace/ThreadEntry.h @@ -14,26 +14,13 @@ * limitations under the License. */ -#ifndef _LIBBACKTRACE_BACKTRACE_THREAD_H -#define _LIBBACKTRACE_BACKTRACE_THREAD_H +#ifndef _LIBBACKTRACE_THREAD_ENTRY_H +#define _LIBBACKTRACE_THREAD_ENTRY_H -#include <inttypes.h> #include <pthread.h> -#include <signal.h> -#include <string.h> #include <sys/types.h> #include <ucontext.h> -#include "BacktraceImpl.h" - -// The signal used to cause a thread to dump the stack. -#if defined(__GLIBC__) -// GLIBC reserves __SIGRTMIN signals, so use SIGRTMIN to avoid errors. -#define THREAD_SIGNAL SIGRTMIN -#else -#define THREAD_SIGNAL (__SIGRTMIN+1) -#endif - class ThreadEntry { public: static ThreadEntry* Get(pid_t pid, pid_t tid, bool create = true); @@ -81,12 +68,4 @@ private: static pthread_mutex_t list_mutex_; }; -class BacktraceThread : public BacktraceCurrent { -public: - BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map); - virtual ~BacktraceThread(); - - virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext); -}; - -#endif // _LIBBACKTRACE_BACKTRACE_THREAD_H +#endif // _LIBBACKTRACE_THREAD_ENTRY_H diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp index 372555b..67e583f 100755..100644 --- a/libbacktrace/UnwindCurrent.cpp +++ b/libbacktrace/UnwindCurrent.cpp @@ -14,41 +14,30 @@ * limitations under the License. */ -#include <sys/types.h> +#include <stdint.h> #include <ucontext.h> -#include <backtrace/Backtrace.h> -#include <backtrace/BacktraceMap.h> +#include <memory> +#include <string> #define UNW_LOCAL_ONLY #include <libunwind.h> +#include <backtrace/Backtrace.h> + #include "BacktraceLog.h" -#include "BacktraceThread.h" #include "UnwindCurrent.h" -#include "UnwindMap.h" - -//------------------------------------------------------------------------- -// UnwindCurrent functions. -//------------------------------------------------------------------------- -UnwindCurrent::UnwindCurrent() { -} - -UnwindCurrent::~UnwindCurrent() { -} -bool UnwindCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { - if (!ucontext) { - int ret = unw_getcontext(&context_); - if (ret < 0) { - BACK_LOGW("unw_getcontext failed %d", ret); - return false; - } - } - else { - GetUnwContextFromUcontext(ucontext); +std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { + *offset = 0; + char buf[512]; + unw_word_t value; + if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf), + &value, &context_) >= 0 && buf[0] != '\0') { + *offset = static_cast<uintptr_t>(value); + return buf; } - return UnwindFromContext(num_ignore_frames, false); + return ""; } void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) { @@ -76,89 +65,67 @@ void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) { #endif } -std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { - *offset = 0; - char buf[512]; - unw_word_t value; - if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf), - &value, &context_) >= 0 && buf[0] != '\0') { - *offset = static_cast<uintptr_t>(value); - return buf; +bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) { + if (ucontext == nullptr) { + int ret = unw_getcontext(&context_); + if (ret < 0) { + BACK_LOGW("unw_getcontext failed %d", ret); + return false; + } + } else { + GetUnwContextFromUcontext(ucontext); } - return ""; -} -bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool within_handler) { // The cursor structure is pretty large, do not put it on the stack. - unw_cursor_t* cursor = new unw_cursor_t; - int ret = unw_init_local(cursor, &context_); + std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t); + int ret = unw_init_local(cursor.get(), &context_); if (ret < 0) { - if (!within_handler) { - BACK_LOGW("unw_init_local failed %d", ret); - } - delete cursor; + BACK_LOGW("unw_init_local failed %d", ret); return false; } - std::vector<backtrace_frame_data_t>* frames = GetFrames(); - frames->reserve(MAX_BACKTRACE_FRAMES); size_t num_frames = 0; do { unw_word_t pc; - ret = unw_get_reg(cursor, UNW_REG_IP, &pc); + ret = unw_get_reg(cursor.get(), UNW_REG_IP, &pc); if (ret < 0) { - if (!within_handler) { - BACK_LOGW("Failed to read IP %d", ret); - } + BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; - ret = unw_get_reg(cursor, UNW_REG_SP, &sp); + ret = unw_get_reg(cursor.get(), UNW_REG_SP, &sp); if (ret < 0) { - if (!within_handler) { - BACK_LOGW("Failed to read SP %d", ret); - } + BACK_LOGW("Failed to read SP %d", ret); break; } - if (num_ignore_frames == 0) { - frames->resize(num_frames+1); - backtrace_frame_data_t* frame = &frames->at(num_frames); - frame->num = num_frames; - frame->pc = static_cast<uintptr_t>(pc); - frame->sp = static_cast<uintptr_t>(sp); - frame->stack_size = 0; - - if (num_frames > 0) { - // Set the stack size for the previous frame. - backtrace_frame_data_t* prev = &frames->at(num_frames-1); - prev->stack_size = frame->sp - prev->sp; - } - - if (!within_handler) { + frames_.resize(num_frames+1); + backtrace_frame_data_t* frame = &frames_.at(num_frames); + frame->num = num_frames; + frame->pc = static_cast<uintptr_t>(pc); + frame->sp = static_cast<uintptr_t>(sp); + frame->stack_size = 0; + + FillInMap(frame->pc, &frame->map); + // Check to see if we should skip this frame because it's coming + // from within the library, and we are doing a local unwind. + if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) { + if (num_ignore_frames == 0) { + // GetFunctionName is an expensive call, only do it if we are + // keeping the frame. frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); - FillInMap(frame->pc, &frame->map); + if (num_frames > 0) { + // Set the stack size for the previous frame. + backtrace_frame_data_t* prev = &frames_.at(num_frames-1); + prev->stack_size = frame->sp - prev->sp; + } + num_frames++; } else { - frame->func_offset = 0; + num_ignore_frames--; } - num_frames++; - } else { - num_ignore_frames--; } - ret = unw_step (cursor); + ret = unw_step (cursor.get()); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); - delete cursor; return true; } - -//------------------------------------------------------------------------- -// C++ object creation function. -//------------------------------------------------------------------------- -Backtrace* CreateCurrentObj(BacktraceMap* map) { - return new BacktraceCurrent(new UnwindCurrent(), map); -} - -Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) { - return new BacktraceThread(new UnwindCurrent(), tid, map); -} diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h index 2375e6e..3023996 100644 --- a/libbacktrace/UnwindCurrent.h +++ b/libbacktrace/UnwindCurrent.h @@ -17,27 +17,32 @@ #ifndef _LIBBACKTRACE_UNWIND_CURRENT_H #define _LIBBACKTRACE_UNWIND_CURRENT_H +#include <stdint.h> +#include <sys/types.h> +#include <ucontext.h> + #include <string> -#include "BacktraceImpl.h" +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> + +#include "BacktraceCurrent.h" #define UNW_LOCAL_ONLY #include <libunwind.h> -class UnwindCurrent : public BacktraceImpl { +class UnwindCurrent : public BacktraceCurrent { public: - UnwindCurrent(); - virtual ~UnwindCurrent(); - - virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext); + UnwindCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : BacktraceCurrent(pid, tid, map) {} + virtual ~UnwindCurrent() {} - virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); + std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override; - bool UnwindFromContext(size_t num_ignore_frames, bool within_handler); +private: + void GetUnwContextFromUcontext(const ucontext_t* ucontext); - void GetUnwContextFromUcontext(const ucontext_t* context); + bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override; -protected: unw_context_t context_; }; diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp index 284a561..fa59d07 100644 --- a/libbacktrace/UnwindMap.cpp +++ b/libbacktrace/UnwindMap.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <pthread.h> +#include <stdint.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> @@ -142,7 +142,7 @@ BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) { } if (!map->Build()) { delete map; - return NULL; + return nullptr; } return map; } diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h index be8855e..e292016 100644 --- a/libbacktrace/UnwindMap.h +++ b/libbacktrace/UnwindMap.h @@ -17,6 +17,9 @@ #ifndef _LIBBACKTRACE_UNWIND_MAP_H #define _LIBBACKTRACE_UNWIND_MAP_H +#include <stdint.h> +#include <sys/types.h> + #include <backtrace/BacktraceMap.h> // The unw_map_cursor_t structure is different depending on whether it is diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp index efe758b..a7c3de5 100644 --- a/libbacktrace/UnwindPtrace.cpp +++ b/libbacktrace/UnwindPtrace.cpp @@ -14,35 +14,36 @@ * limitations under the License. */ -#include <backtrace/Backtrace.h> -#include <backtrace/BacktraceMap.h> - +#include <stdint.h> #include <sys/types.h> -#include <string.h> #include <ucontext.h> #include <libunwind.h> #include <libunwind-ptrace.h> +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> + #include "BacktraceLog.h" #include "UnwindMap.h" #include "UnwindPtrace.h" -UnwindPtrace::UnwindPtrace() : addr_space_(NULL), upt_info_(NULL) { +UnwindPtrace::UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map) + : BacktracePtrace(pid, tid, map), addr_space_(nullptr), upt_info_(nullptr) { } UnwindPtrace::~UnwindPtrace() { if (upt_info_) { _UPT_destroy(upt_info_); - upt_info_ = NULL; + upt_info_ = nullptr; } if (addr_space_) { // Remove the map from the address space before destroying it. // It will be freed in the UnwindMap destructor. - unw_map_set(addr_space_, NULL); + unw_map_set(addr_space_, nullptr); unw_destroy_addr_space(addr_space_); - addr_space_ = NULL; + addr_space_ = nullptr; } } @@ -74,8 +75,6 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { return false; } - std::vector<backtrace_frame_data_t>* frames = GetFrames(); - frames->reserve(MAX_BACKTRACE_FRAMES); size_t num_frames = 0; do { unw_word_t pc; @@ -92,15 +91,15 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { } if (num_ignore_frames == 0) { - frames->resize(num_frames+1); - backtrace_frame_data_t* frame = &frames->at(num_frames); + frames_.resize(num_frames+1); + backtrace_frame_data_t* frame = &frames_.at(num_frames); frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; if (num_frames > 0) { - backtrace_frame_data_t* prev = &frames->at(num_frames-1); + backtrace_frame_data_t* prev = &frames_.at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } @@ -129,10 +128,3 @@ std::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { } return ""; } - -//------------------------------------------------------------------------- -// C++ object creation function. -//------------------------------------------------------------------------- -Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map) { - return new BacktracePtrace(new UnwindPtrace(), pid, tid, map); -} diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h index 2fb7967..ab04abf 100644 --- a/libbacktrace/UnwindPtrace.h +++ b/libbacktrace/UnwindPtrace.h @@ -17,20 +17,26 @@ #ifndef _LIBBACKTRACE_UNWIND_PTRACE_H #define _LIBBACKTRACE_UNWIND_PTRACE_H -#include <string> +#include <stdint.h> +#include <sys/types.h> -#include "BacktraceImpl.h" +#include <string> +#ifdef UNW_LOCAL_ONLY +#undef UNW_LOCAL_ONLY +#endif #include <libunwind.h> -class UnwindPtrace : public BacktraceImpl { +#include "BacktracePtrace.h" + +class UnwindPtrace : public BacktracePtrace { public: - UnwindPtrace(); + UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map); virtual ~UnwindPtrace(); - virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext); + bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override; - virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); + std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override; private: unw_addr_space_t addr_space_; diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp index b1e34bd..4af6592 100644 --- a/libbacktrace/backtrace_test.cpp +++ b/libbacktrace/backtrace_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define _GNU_SOURCE 1 #include <dirent.h> #include <errno.h> #include <inttypes.h> @@ -33,13 +34,14 @@ #include <backtrace/BacktraceMap.h> // For the THREAD_SIGNAL definition. -#include "BacktraceThread.h" +#include "BacktraceCurrent.h" #include <cutils/atomic.h> #include <gtest/gtest.h> #include <algorithm> #include <memory> +#include <string> #include <vector> #include "thread_utils.h" @@ -83,15 +85,16 @@ uint64_t NanoTime() { return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec); } -void DumpFrames(Backtrace* backtrace) { +std::string DumpFrames(Backtrace* backtrace) { if (backtrace->NumFrames() == 0) { - printf(" No frames to dump\n"); - return; + return " No frames to dump.\n"; } + std::string frame; for (size_t i = 0; i < backtrace->NumFrames(); i++) { - printf(" %s\n", backtrace->FormatFrameData(i).c_str()); + frame += " " + backtrace->FormatFrameData(i) + '\n'; } + return frame; } void WaitForStop(pid_t pid) { @@ -121,8 +124,10 @@ bool ReadyLevelBacktrace(Backtrace* backtrace) { } void VerifyLevelDump(Backtrace* backtrace) { - ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0)); - ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)); + ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0)) + << DumpFrames(backtrace); + ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)) + << DumpFrames(backtrace); // Look through the frames starting at the highest to find the // frame we want. @@ -133,13 +138,17 @@ void VerifyLevelDump(Backtrace* backtrace) { break; } } - ASSERT_LT(static_cast<size_t>(0), frame_num); - ASSERT_LE(static_cast<size_t>(3), frame_num); - - ASSERT_EQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one"); - ASSERT_EQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two"); - ASSERT_EQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three"); - ASSERT_EQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four"); + ASSERT_LT(static_cast<size_t>(0), frame_num) << DumpFrames(backtrace); + ASSERT_LE(static_cast<size_t>(3), frame_num) << DumpFrames(backtrace); + + ASSERT_EQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one") + << DumpFrames(backtrace); + ASSERT_EQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two") + << DumpFrames(backtrace); + ASSERT_EQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three") + << DumpFrames(backtrace); + ASSERT_EQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four") + << DumpFrames(backtrace); } void VerifyLevelBacktrace(void*) { @@ -156,10 +165,11 @@ bool ReadyMaxBacktrace(Backtrace* backtrace) { } void VerifyMaxDump(Backtrace* backtrace) { - ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)); + ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)) + << DumpFrames(backtrace); // Verify that the last frame is our recursive call. - ASSERT_EQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name, - "test_recursive_call"); + ASSERT_EQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name, "test_recursive_call") + << DumpFrames(backtrace); } void VerifyMaxBacktrace(void*) { @@ -198,6 +208,24 @@ bool WaitForNonZero(int32_t* value, uint64_t seconds) { return false; } +TEST(libbacktrace, local_no_unwind_frames) { + // Verify that a local unwind does not include any frames within + // libunwind or libbacktrace. + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid())); + ASSERT_TRUE(backtrace.get() != nullptr); + ASSERT_TRUE(backtrace->Unwind(0)); + + ASSERT_TRUE(backtrace->NumFrames() != 0); + for (const auto& frame : *backtrace ) { + if (BacktraceMap::IsValid(frame.map)) { + const std::string name = basename(frame.map.name.c_str()); + ASSERT_TRUE(name != "libunwind.so" && name != "libbacktrace.so") + << DumpFrames(backtrace.get()); + } + break; + } +} + TEST(libbacktrace, local_trace) { ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0); } @@ -205,8 +233,10 @@ TEST(libbacktrace, local_trace) { void VerifyIgnoreFrames( Backtrace* bt_all, Backtrace* bt_ign1, Backtrace* bt_ign2, const char* cur_proc) { - EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1); - EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2); + EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1) + << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 1 backtrace:\n" << DumpFrames(bt_ign1); + EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2) + << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 2 backtrace:\n" << DumpFrames(bt_ign2); // Check all of the frames are the same > the current frame. bool check = (cur_proc == nullptr); @@ -264,6 +294,7 @@ void VerifyProcTest(pid_t pid, pid_t tid, bool share_map, } uint64_t start = NanoTime(); bool verified = false; + std::string last_dump; do { usleep(US_PER_MSEC); if (ptrace(PTRACE_ATTACH, ptrace_tid, 0, 0) == 0) { @@ -275,18 +306,20 @@ void VerifyProcTest(pid_t pid, pid_t tid, bool share_map, map.reset(BacktraceMap::Create(pid)); } std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get())); - ASSERT_TRUE(backtrace->Unwind(0)); ASSERT_TRUE(backtrace.get() != nullptr); + ASSERT_TRUE(backtrace->Unwind(0)); if (ReadyFunc(backtrace.get())) { VerifyFunc(backtrace.get()); verified = true; + } else { + last_dump = DumpFrames(backtrace.get()); } ASSERT_TRUE(ptrace(PTRACE_DETACH, ptrace_tid, 0, 0) == 0); } // If 5 seconds have passed, then we are done. } while (!verified && (NanoTime() - start) <= 5 * NS_PER_SEC); - ASSERT_TRUE(verified); + ASSERT_TRUE(verified) << "Last backtrace:\n" << last_dump; } TEST(libbacktrace, ptrace_trace) { @@ -490,9 +523,13 @@ TEST(libbacktrace, thread_level_trace) { // The SA_RESTORER flag gets set behind our back, so a direct comparison // doesn't work unless we mask the value off. Mips doesn't have this // flag, so skip this on that platform. -#ifdef SA_RESTORER +#if defined(SA_RESTORER) cur_action.sa_flags &= ~SA_RESTORER; new_action.sa_flags &= ~SA_RESTORER; +#elif defined(__GLIBC__) + // Our host compiler doesn't appear to define this flag for some reason. + cur_action.sa_flags &= ~0x04000000; + new_action.sa_flags &= ~0x04000000; #endif EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags); } @@ -674,16 +711,19 @@ TEST(libbacktrace, simultaneous_maps) { BacktraceMap* map3 = BacktraceMap::Create(getpid()); Backtrace* back1 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map1); + ASSERT_TRUE(back1 != nullptr); EXPECT_TRUE(back1->Unwind(0)); delete back1; delete map1; Backtrace* back2 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map2); + ASSERT_TRUE(back2 != nullptr); EXPECT_TRUE(back2->Unwind(0)); delete back2; delete map2; Backtrace* back3 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map3); + ASSERT_TRUE(back3 != nullptr); EXPECT_TRUE(back3->Unwind(0)); delete back3; delete map3; @@ -858,10 +898,15 @@ void* ThreadReadTest(void* data) { // Tell the caller it's okay to start reading memory. android_atomic_acquire_store(1, &thread_data->state); - // Loop waiting for everything + // Loop waiting for the caller to finish reading the memory. while (thread_data->state) { } + // Re-enable read-write on the page so that we don't crash if we try + // and access data on this page when freeing the memory. + if (mprotect(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) != 0) { + return reinterpret_cast<void*>(-1); + } free(memory); android_atomic_acquire_store(1, &thread_data->state); @@ -960,6 +1005,7 @@ TEST(libbacktrace, process_read) { WaitForStop(pid); std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid)); + ASSERT_TRUE(backtrace.get() != nullptr); uintptr_t read_addr; size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(&g_ready), @@ -1005,6 +1051,7 @@ void CheckForLeak(pid_t pid, pid_t tid) { delete backtrace; } size_t stable_pss = GetPssBytes(); + ASSERT_TRUE(stable_pss != 0); // Loop enough that even a small leak should be detectable. for (size_t i = 0; i < 4096; i++) { @@ -1014,6 +1061,7 @@ void CheckForLeak(pid_t pid, pid_t tid) { delete backtrace; } size_t new_pss = GetPssBytes(); + ASSERT_TRUE(new_pss != 0); size_t abs_diff = (new_pss > stable_pss) ? new_pss - stable_pss : stable_pss - new_pss; // As long as the new pss is within a certain amount, consider everything okay. ASSERT_LE(abs_diff, MAX_LEAK_BYTES); diff --git a/libcutils/Android.mk b/libcutils/Android.mk index d890319..c636196 100644 --- a/libcutils/Android.mk +++ b/libcutils/Android.mk @@ -22,6 +22,7 @@ commonSources := \ native_handle.c \ config_utils.c \ load_file.c \ + strlcpy.c \ open_memstream.c \ strdup16to8.c \ strdup8to16.c \ @@ -31,6 +32,7 @@ commonSources := \ sched_policy.c \ iosched_policy.c \ str_parms.c \ + fs_config.c # some files must not be compiled when building against Mingw # they correspond to features not used by our host development tools @@ -59,7 +61,8 @@ ifneq ($(WINDOWS_HOST_ONLY),1) sockets.c \ commonHostSources += \ - ashmem-host.c + ashmem-host.c \ + trace-host.c endif @@ -73,7 +76,6 @@ ifneq ($(HOST_OS),windows) LOCAL_CFLAGS += -Werror endif LOCAL_MULTILIB := both -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_HOST_STATIC_LIBRARY) include $(CLEAR_VARS) @@ -84,22 +86,8 @@ ifneq ($(HOST_OS),windows) LOCAL_CFLAGS += -Werror endif LOCAL_MULTILIB := both -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_HOST_SHARED_LIBRARY) -# Tests for host -# ======================================================== -include $(CLEAR_VARS) -LOCAL_MODULE := tst_str_parms -LOCAL_CFLAGS += -DTEST_STR_PARMS -ifneq ($(HOST_OS),windows) -LOCAL_CFLAGS += -Werror -endif -LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c -LOCAL_STATIC_LIBRARIES := liblog -LOCAL_MODULE_TAGS := optional -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -include $(BUILD_HOST_EXECUTABLE) # Shared and static library for target @@ -112,32 +100,19 @@ LOCAL_SRC_FILES := $(commonSources) \ ashmem-dev.c \ debugger.c \ klog.c \ - memory.c \ partition_utils.c \ properties.c \ qtaguid.c \ - trace.c \ + trace-dev.c \ uevent.c \ -LOCAL_SRC_FILES_arm += \ - arch-arm/memset32.S \ - # arch-arm/memset32.S does not compile with Clang. LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as -LOCAL_SRC_FILES_arm64 += \ - arch-arm64/android_memset.S \ - -ifndef ARCH_MIPS_REV6 -LOCAL_SRC_FILES_mips += \ - arch-mips/android_memset.c \ - -LOCAL_CFLAGS_mips += -DHAVE_MEMSET16 -DHAVE_MEMSET32 -endif - -# TODO: switch mips64 back to using arch-mips/android_memset.c -LOCAL_SRC_FILES_mips64 += \ -# arch-mips/android_memset.c \ +LOCAL_SRC_FILES_arm += arch-arm/memset32.S +LOCAL_SRC_FILES_arm64 += arch-arm64/android_memset.S +LOCAL_SRC_FILES_mips += arch-mips/android_memset.S +LOCAL_SRC_FILES_mips64 += arch-mips/android_memset.S LOCAL_SRC_FILES_x86 += \ arch-x86/android_memset16.S \ @@ -147,16 +122,9 @@ LOCAL_SRC_FILES_x86_64 += \ arch-x86_64/android_memset16.S \ arch-x86_64/android_memset32.S \ -LOCAL_CFLAGS_arm += -DHAVE_MEMSET16 -DHAVE_MEMSET32 -LOCAL_CFLAGS_arm64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32 -#LOCAL_CFLAGS_mips64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32 -LOCAL_CFLAGS_x86 += -DHAVE_MEMSET16 -DHAVE_MEMSET32 -LOCAL_CFLAGS_x86_64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32 - LOCAL_C_INCLUDES := $(libcutils_c_includes) LOCAL_STATIC_LIBRARIES := liblog LOCAL_CFLAGS += -Werror -std=gnu90 -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) @@ -167,16 +135,6 @@ LOCAL_WHOLE_STATIC_LIBRARIES := libcutils liblog LOCAL_SHARED_LIBRARIES := liblog LOCAL_CFLAGS += -Werror LOCAL_C_INCLUDES := $(libcutils_c_includes) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_SHARED_LIBRARY) -include $(CLEAR_VARS) -LOCAL_MODULE := tst_str_parms -LOCAL_CFLAGS += -DTEST_STR_PARMS -Werror -LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c -LOCAL_SHARED_LIBRARIES := liblog -LOCAL_MODULE_TAGS := optional -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -include $(BUILD_EXECUTABLE) - include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/libcutils/arch-mips/android_memset.S b/libcutils/arch-mips/android_memset.S new file mode 100644 index 0000000..6811de0 --- /dev/null +++ b/libcutils/arch-mips/android_memset.S @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2009 + * MIPS Technologies, Inc., California. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/************************************************************************ + * + * memset.S, version "64h" with 1 cache line horizon for "pref 30" and 14 nops + * Version: "043009" + * + ************************************************************************/ + + +/************************************************************************ + * Include files + ************************************************************************/ + +#include <machine/asm.h> +#define END(f) .cfi_endproc; .size f, .-f; .end f + +/* + * This routine could be optimized for MIPS64. The current code only + * uses MIPS32 instructions. + */ + +#if defined(__MIPSEB__) +# define SWHI swl /* high part is left in big-endian */ +# define SWLO swr /* low part is right in big-endian */ +#endif + +#if defined(__MIPSEL__) +# define SWHI swr /* high part is right in little-endian */ +# define SWLO swl /* low part is left in little-endian */ +#endif + +#if !(defined(XGPROF) || defined(XPROF)) +#undef SETUP_GP +#define SETUP_GP +#endif + +#ifdef NDEBUG +#define DBG # +#else +#define DBG +#endif + +/* + * void android_memset16(uint16_t* dst, uint16_t value, size_t size); + */ + +LEAF(android_memset16,0) + .set noreorder +DBG /* Check parameters */ +DBG andi t0,a0,1 # a0 must be halfword aligned +DBG tne t0,zero +DBG andi t2,a2,1 # a2 must be even +DBG tne t2,zero + +#ifdef FIXARGS + # ensure count is even +#if (__mips==32) && (__mips_isa_rev>=2) + ins a2,zero,0,1 +#else + ori a2,1 + xori a2,1 +#endif +#endif + +#if (__mips==32) && (__mips_isa_rev>=2) + ins a1,a1,16,16 +#else + andi a1,0xffff + sll t3,a1,16 + or a1,t3 +#endif + + beqz a2,.Ldone + andi t1,a0,2 + beqz t1,.Lalignok + addu t0,a0,a2 # t0 is the "past the end" address + sh a1,0(a0) # store one halfword to get aligned + addu a0,2 + subu a2,2 +.Lalignok: + slti t1,a2,4 # .Laligned for 4 or more bytes + beqz t1,.Laligned + sne t1,a2,2 # one more halfword? + bnez t1,.Ldone + nop + sh a1,0(a0) +.Ldone: + j ra + nop + .set reorder +END(android_memset16) + +/* + * void android_memset32(uint32_t* dst, uint32_t value, size_t size); + */ + +LEAF(android_memset32,0) + .set noreorder +DBG /* Check parameters */ +DBG andi t0,a0,3 # a0 must be word aligned +DBG tne t0,zero +DBG andi t2,a2,3 # a2 must be a multiple of 4 bytes +DBG tne t2,zero + +#ifdef FIXARGS + # ensure count is a multiple of 4 +#if (__mips==32) && (__mips_isa_rev>=2) + ins $a2,$0,0,2 +#else + ori a2,3 + xori a2,3 +#endif +#endif + + bnez a2,.Laligned # any work to do? + addu t0,a0,a2 # t0 is the "past the end" address + + j ra + nop + .set reorder +END(android_memset32) + +LEAF(memset,0) + + .set noreorder + .set noat + + addu t0,a0,a2 # t0 is the "past the end" address + slti AT,a2,4 # is a2 less than 4? + bne AT,zero,.Llast4 # if yes, go to last4 + move v0,a0 # memset returns the dst pointer + + beq a1,zero,.Lset0 + subu v1,zero,a0 + + # smear byte into 32 bit word +#if (__mips==32) && (__mips_isa_rev>=2) + ins a1, a1, 8, 8 # Replicate fill byte into half-word. + ins a1, a1, 16, 16 # Replicate fill byte into word. +#else + and a1,0xff + sll AT,a1,8 + or a1,AT + sll AT,a1,16 + or a1,AT +#endif + +.Lset0: + andi v1,v1,0x3 # word-unaligned address? + beq v1,zero,.Laligned # v1 is the unalignment count + subu a2,a2,v1 + SWHI a1,0(a0) + addu a0,a0,v1 + +# Here we have the "word-aligned" a0 (until the "last4") +.Laligned: + andi t8,a2,0x3f # any 64-byte chunks? + # t8 is the byte count past 64-byte chunks + beq a2,t8,.Lchk8w # when a2==t8, no 64-byte chunks + # There will be at most 1 32-byte chunk then + subu a3,a2,t8 # subtract from a2 the reminder + # Here a3 counts bytes in 16w chunks + addu a3,a0,a3 # Now a3 is the final dst after 64-byte chunks + +# Find out, if there are any 64-byte chunks after which will be still at least +# 96 bytes left. The value "96" is calculated as needed buffer for +# "pref 30,64(a0)" prefetch, which can be used as "pref 30,0(a0)" after +# incrementing "a0" by 64. +# For "a2" below 160 there will be no such "pref 30 safe" 64-byte chunk. +# + sltiu v1,a2,160 + bgtz v1,.Lloop16w_nopref30 # skip "pref 30,0(a0)" + subu t7,a2,96 # subtract "pref 30 unsafe" region + # below we have at least 1 64-byte chunk which is "pref 30 safe" + andi t6,t7,0x3f # t6 is past "64-byte safe chunks" reminder + subu t5,t7,t6 # subtract from t7 the reminder + # Here t5 counts bytes in 16w "safe" chunks + addu t4,a0,t5 # Now t4 is the dst after 64-byte "safe" chunks + +# Don't use "pref 30,0(a0)" for a0 in a "middle" of a cache line +# pref 30,0(a0) +# Here we are in the region, where it is safe to use "pref 30,64(a0)" +.Lloop16w: + addiu a0,a0,64 + pref 30,-32(a0) # continue setting up the dest, addr 64-32 + sw a1,-64(a0) + sw a1,-60(a0) + sw a1,-56(a0) + sw a1,-52(a0) + sw a1,-48(a0) + sw a1,-44(a0) + sw a1,-40(a0) + sw a1,-36(a0) + nop + nop # the extra nop instructions help to balance + nop # cycles needed for "store" + "fill" + "evict" + nop # For 64byte store there are needed 8 fill + nop # and 8 evict cycles, i.e. at least 32 instr. + nop + nop + pref 30,0(a0) # continue setting up the dest, addr 64-0 + sw a1,-32(a0) + sw a1,-28(a0) + sw a1,-24(a0) + sw a1,-20(a0) + sw a1,-16(a0) + sw a1,-12(a0) + sw a1,-8(a0) + sw a1,-4(a0) + nop + nop + nop + nop # NOTE: adding 14 nop-s instead of 12 nop-s + nop # gives better results for "fast" memory + nop + bne a0,t4,.Lloop16w + nop + + beq a0,a3,.Lchk8w # maybe no more 64-byte chunks? + nop # this "delayed slot" is useless ... + +.Lloop16w_nopref30: # there could be up to 3 "64-byte nopref30" chunks + addiu a0,a0,64 + sw a1,-64(a0) + sw a1,-60(a0) + sw a1,-56(a0) + sw a1,-52(a0) + sw a1,-48(a0) + sw a1,-44(a0) + sw a1,-40(a0) + sw a1,-36(a0) + sw a1,-32(a0) + sw a1,-28(a0) + sw a1,-24(a0) + sw a1,-20(a0) + sw a1,-16(a0) + sw a1,-12(a0) + sw a1,-8(a0) + bne a0,a3,.Lloop16w_nopref30 + sw a1,-4(a0) + +.Lchk8w: # t8 here is the byte count past 64-byte chunks + + andi t7,t8,0x1f # is there a 32-byte chunk? + # the t7 is the reminder count past 32-bytes + beq t8,t7,.Lchk1w # when t8==t7, no 32-byte chunk + move a2,t7 + + sw a1,0(a0) + sw a1,4(a0) + sw a1,8(a0) + sw a1,12(a0) + sw a1,16(a0) + sw a1,20(a0) + sw a1,24(a0) + sw a1,28(a0) + addiu a0,a0,32 + +.Lchk1w: + andi t8,a2,0x3 # now t8 is the reminder past 1w chunks + beq a2,t8,.Llast4aligned + subu a3,a2,t8 # a3 is the count of bytes in 1w chunks + addu a3,a0,a3 # now a3 is the dst address past the 1w chunks + +# copying in words (4-byte chunks) +.LwordCopy_loop: + addiu a0,a0,4 + bne a0,a3,.LwordCopy_loop + sw a1,-4(a0) + +# store last 0-3 bytes +# this will repeat the last store if the memset finishes on a word boundary +.Llast4aligned: + j ra + SWLO a1,-1(t0) + +.Llast4: + beq a0,t0,.Llast4e +.Llast4l: + addiu a0,a0,1 + bne a0,t0,.Llast4l + sb a1,-1(a0) +.Llast4e: + j ra + nop + + .set at + .set reorder + +END(memset) + + +/************************************************************************ + * Implementation : Static functions + ************************************************************************/ diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c new file mode 100644 index 0000000..659f614 --- /dev/null +++ b/libcutils/fs_config.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2007 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. + */ + +/* This file is used to define the properties of the filesystem +** images generated by build tools (mkbootfs and mkyaffs2image) and +** by the device side of adb. +*/ + +#include <stdint.h> +#include <string.h> +#include <sys/stat.h> + +#include <private/android_filesystem_config.h> + +/* Rules for directories. +** These rules are applied based on "first match", so they +** should start with the most specific path and work their +** way up to the root. +*/ + +static const struct fs_path_config android_dirs[] = { + { 00770, AID_SYSTEM, AID_CACHE, 0, "cache" }, + { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" }, + { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" }, + { 00771, AID_ROOT, AID_ROOT, 0, "data/dalvik-cache" }, + { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" }, + { 00771, AID_SHELL, AID_SHELL, 0, "data/local/tmp" }, + { 00771, AID_SHELL, AID_SHELL, 0, "data/local" }, + { 01771, AID_SYSTEM, AID_MISC, 0, "data/misc" }, + { 00770, AID_DHCP, AID_DHCP, 0, "data/misc/dhcp" }, + { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" }, + { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" }, + { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" }, + { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" }, + { 00750, AID_ROOT, AID_SHELL, 0, "sbin" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/bin" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin" }, + { 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" }, + { 00755, AID_ROOT, AID_SHELL, 0, "vendor" }, + { 00777, AID_ROOT, AID_ROOT, 0, "sdcard" }, + { 00755, AID_ROOT, AID_ROOT, 0, 0 }, +}; + +/* Rules for files. +** These rules are applied based on "first match", so they +** should start with the most specific path and work their +** way up to the root. Prefixes ending in * denotes wildcard +** and will allow partial matches. +*/ +static const struct fs_path_config android_files[] = { + { 00440, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.rc" }, + { 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.sh" }, + { 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.ril" }, + { 00550, AID_DHCP, AID_SHELL, 0, "system/etc/dhcpcd/dhcpcd-run-hooks" }, + { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" }, + { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" }, + { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" }, + { 00644, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/*" }, + { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" }, + { 00644, AID_APP, AID_APP, 0, "data/data/*" }, + + /* the following five files are INTENTIONALLY set-uid, but they + * are NOT included on user builds. */ + { 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" }, + { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" }, + { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procrank" }, + { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" }, + { 04770, AID_ROOT, AID_RADIO, 0, "system/bin/pppd-ril" }, + + /* the following files have enhanced capabilities and ARE included in user builds. */ + { 00750, AID_ROOT, AID_SHELL, (1ULL << CAP_SETUID) | (1ULL << CAP_SETGID), "system/bin/run-as" }, + { 00700, AID_SYSTEM, AID_SHELL, (1ULL << CAP_BLOCK_SUSPEND), "system/bin/inputflinger" }, + + { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" }, + { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" }, + { 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" }, + { 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor/bin/*" }, + { 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" }, + { 00750, AID_ROOT, AID_SHELL, 0, "sbin/*" }, + { 00755, AID_ROOT, AID_ROOT, 0, "bin/*" }, + { 00750, AID_ROOT, AID_SHELL, 0, "init*" }, + { 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" }, + { 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" }, + { 00644, AID_ROOT, AID_ROOT, 0, 0 }, +}; + +void fs_config(const char *path, int dir, + unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities) +{ + const struct fs_path_config *pc; + int plen; + + if (path[0] == '/') { + path++; + } + + pc = dir ? android_dirs : android_files; + plen = strlen(path); + for(; pc->prefix; pc++){ + int len = strlen(pc->prefix); + if (dir) { + if(plen < len) continue; + if(!strncmp(pc->prefix, path, len)) break; + continue; + } + /* If name ends in * then allow partial matches. */ + if (pc->prefix[len -1] == '*') { + if(!strncmp(pc->prefix, path, len - 1)) break; + } else if (plen == len){ + if(!strncmp(pc->prefix, path, len)) break; + } + } + *uid = pc->uid; + *gid = pc->gid; + *mode = (*mode & (~07777)) | pc->mode; + *capabilities = pc->capabilities; +} diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c index a6da9ca..8946d3c 100644 --- a/libcutils/iosched_policy.c +++ b/libcutils/iosched_policy.c @@ -1,5 +1,5 @@ /* -** Copyright 2007-2014, The Android Open Source Project +** Copyright 2007, 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. diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c index dfe8c4b..924289a 100644 --- a/libcutils/str_parms.c +++ b/libcutils/str_parms.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 The Android Open Source Project + * Copyright (C) 2011 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. @@ -357,51 +357,3 @@ void str_parms_dump(struct str_parms *str_parms) { hashmapForEach(str_parms->map, dump_entry, str_parms); } - -#ifdef TEST_STR_PARMS -static void test_str_parms_str(const char *str) -{ - struct str_parms *str_parms; - char *out_str; - - str_parms = str_parms_create_str(str); - str_parms_add_str(str_parms, "dude", "woah"); - str_parms_add_str(str_parms, "dude", "woah"); - str_parms_del(str_parms, "dude"); - str_parms_dump(str_parms); - out_str = str_parms_to_str(str_parms); - str_parms_destroy(str_parms); - ALOGI("%s: '%s' stringified is '%s'", __func__, str, out_str); - free(out_str); -} - -int main(void) -{ - test_str_parms_str(""); - test_str_parms_str(";"); - test_str_parms_str("="); - test_str_parms_str("=;"); - test_str_parms_str("=bar"); - test_str_parms_str("=bar;"); - test_str_parms_str("foo="); - test_str_parms_str("foo=;"); - test_str_parms_str("foo=bar"); - test_str_parms_str("foo=bar;"); - test_str_parms_str("foo=bar;baz"); - test_str_parms_str("foo=bar;baz="); - test_str_parms_str("foo=bar;baz=bat"); - test_str_parms_str("foo=bar;baz=bat;"); - test_str_parms_str("foo=bar;baz=bat;foo=bar"); - - // hashmapPut reports errors by setting errno to ENOMEM. - // Test that we're not confused by running in an environment where this is already true. - errno = ENOMEM; - test_str_parms_str("foo=bar;baz="); - if (errno != ENOMEM) { - abort(); - } - test_str_parms_str("foo=bar;baz="); - - return 0; -} -#endif diff --git a/libcutils/memory.c b/libcutils/strlcpy.c index 6486b45..c66246c 100644 --- a/libcutils/memory.c +++ b/libcutils/strlcpy.c @@ -1,43 +1,4 @@ /* - * Copyright (C) 2007 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. - */ - -#include <cutils/memory.h> - -#if !HAVE_MEMSET16 -void android_memset16(uint16_t* dst, uint16_t value, size_t size) -{ - size >>= 1; - while (size--) { - *dst++ = value; - } -} -#endif - -#if !HAVE_MEMSET32 -void android_memset32(uint32_t* dst, uint32_t value, size_t size) -{ - size >>= 2; - while (size--) { - *dst++ = value; - } -} -#endif - -#if !HAVE_STRLCPY -/* * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> * * Permission to use, copy, modify, and distribute this software for any @@ -54,8 +15,13 @@ void android_memset32(uint32_t* dst, uint32_t value, size_t size) */ #include <sys/types.h> + +#if defined(__GLIBC__) || defined(_WIN32) + #include <string.h> +#include <cutils/memory.h> + /* Implementation of strlcpy() for platforms that don't already have it. */ /* @@ -88,4 +54,5 @@ strlcpy(char *dst, const char *src, size_t siz) return(s - src - 1); /* count does not include NUL */ } + #endif diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk index 5a54698..cf70345 100644 --- a/libcutils/tests/Android.mk +++ b/libcutils/tests/Android.mk @@ -15,38 +15,59 @@ LOCAL_PATH := $(call my-dir) test_src_files := \ + test_str_parms.cpp \ + +test_target_only_src_files := \ MemsetTest.cpp \ PropertiesTest.cpp \ +test_libraries := libcutils liblog + + +# +# Target. +# + include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := libcutils_test -LOCAL_SRC_FILES := $(test_src_files) -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - liblog \ - libutils \ +LOCAL_SRC_FILES := $(test_src_files) $(test_target_only_src_files) +LOCAL_SHARED_LIBRARIES := $(test_libraries) +LOCAL_MULTILIB := both +LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 +LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 +include $(BUILD_NATIVE_TEST) +include $(CLEAR_VARS) +LOCAL_MODULE := libcutils_test_static +LOCAL_FORCE_STATIC_EXECUTABLE := true +LOCAL_SRC_FILES := $(test_src_files) $(test_target_only_src_files) +LOCAL_STATIC_LIBRARIES := libc $(test_libraries) +LOCAL_CXX_STL := libc++_static LOCAL_MULTILIB := both LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 include $(BUILD_NATIVE_TEST) -# The static libcutils tests cannot be built when using libc++ because there are -# multiple symbol definition errors between libc++ and libgcc. b/18389856 -#include $(CLEAR_VARS) -#LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -#LOCAL_MODULE := libcutils_test_static -#LOCAL_FORCE_STATIC_EXECUTABLE := true -#LOCAL_SRC_FILES := $(test_src_files) -#LOCAL_STATIC_LIBRARIES := \ -# libc \ -# libcutils \ -# liblog \ -# libutils \ - -#LOCAL_CXX_STL := stlport_static -#LOCAL_MULTILIB := both -#LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 -#LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 -#include $(BUILD_NATIVE_TEST) + +# +# Host. +# + +include $(CLEAR_VARS) +LOCAL_MODULE := libcutils_test +LOCAL_SRC_FILES := $(test_src_files) +LOCAL_SHARED_LIBRARIES := $(test_libraries) +LOCAL_MULTILIB := both +LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 +LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 +include $(BUILD_HOST_NATIVE_TEST) + +include $(CLEAR_VARS) +LOCAL_MODULE := libcutils_test_static +LOCAL_SRC_FILES := $(test_src_files) +LOCAL_STATIC_LIBRARIES := $(test_libraries) +LOCAL_CXX_STL := libc++_static +LOCAL_MULTILIB := both +LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 +LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 +include $(BUILD_HOST_NATIVE_TEST) diff --git a/libcutils/tests/test_str_parms.cpp b/libcutils/tests/test_str_parms.cpp new file mode 100644 index 0000000..d8f639b --- /dev/null +++ b/libcutils/tests/test_str_parms.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 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. + */ + +#include <cutils/str_parms.h> +#include <gtest/gtest.h> + +static void test_str_parms_str(const char* str, const char* expected) { + str_parms* str_parms = str_parms_create_str(str); + str_parms_add_str(str_parms, "dude", "woah"); + str_parms_add_str(str_parms, "dude", "woah"); + str_parms_del(str_parms, "dude"); + str_parms_dump(str_parms); + char* out_str = str_parms_to_str(str_parms); + str_parms_destroy(str_parms); + ASSERT_STREQ(expected, out_str) << str; + free(out_str); +} + +TEST(str_parms, smoke) { + test_str_parms_str("", ""); + test_str_parms_str(";", ""); + test_str_parms_str("=", ""); + test_str_parms_str("=;", ""); + test_str_parms_str("=bar", ""); + test_str_parms_str("=bar;", ""); + test_str_parms_str("foo=", "foo="); + test_str_parms_str("foo=;", "foo="); + test_str_parms_str("foo=bar", "foo=bar"); + test_str_parms_str("foo=bar;", "foo=bar"); + test_str_parms_str("foo=bar;baz", "foo=bar;baz="); + test_str_parms_str("foo=bar;baz=", "foo=bar;baz="); + test_str_parms_str("foo=bar;baz=bat", "foo=bar;baz=bat"); + test_str_parms_str("foo=bar;baz=bat;", "foo=bar;baz=bat"); + test_str_parms_str("foo=bar1;baz=bat;foo=bar2", "foo=bar2;baz=bat"); +} + +TEST(str_parms, put_ENOMEM) { + // hashmapPut reports errors by setting errno to ENOMEM. + // Test that we're not confused by running in an environment where this is already true. + errno = ENOMEM; + test_str_parms_str("foo=bar;baz=", "foo=bar;baz="); + ASSERT_EQ(ENOMEM, errno); + test_str_parms_str("foo=bar;baz=", "foo=bar;baz="); +} diff --git a/libcutils/trace.c b/libcutils/trace-dev.c index 4396625..4396625 100644 --- a/libcutils/trace.c +++ b/libcutils/trace-dev.c diff --git a/libcutils/trace-host.c b/libcutils/trace-host.c new file mode 100644 index 0000000..b87e543 --- /dev/null +++ b/libcutils/trace-host.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 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. + */ + +#include <cutils/trace.h> + +#ifndef __unused +#define __unused __attribute__((__unused__)) +#endif + +volatile int32_t atrace_is_ready = 1; +int atrace_marker_fd = -1; +uint64_t atrace_enabled_tags = 0; + +void atrace_set_debuggable(bool debuggable __unused) { } +void atrace_set_tracing_enabled(bool enabled __unused) { } +void atrace_update_tags() { } +void atrace_setup() { } +void atrace_begin_body(const char* name __unused) { } +void atrace_async_begin_body(const char* name __unused, int32_t cookie __unused) { } +void atrace_async_end_body(const char* name __unused, int32_t cookie __unused) { } +void atrace_int_body(const char* name __unused, int32_t value __unused) { } +void atrace_int64_body(const char* name __unused, int64_t value __unused) { } diff --git a/libion/tests/Android.mk b/libion/tests/Android.mk index abf527a..894f90e 100644 --- a/libion/tests/Android.mk +++ b/libion/tests/Android.mk @@ -18,7 +18,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ion-unit-tests -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers LOCAL_SHARED_LIBRARIES += libion LOCAL_C_INCLUDES := $(LOCAL_PATH)/../kernel-headers diff --git a/liblog/logd_write.c b/liblog/logd_write.c index dfe34d1..c62a246 100644 --- a/liblog/logd_write.c +++ b/liblog/logd_write.c @@ -356,43 +356,7 @@ static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) int __android_log_write(int prio, const char *tag, const char *msg) { - struct iovec vec[3]; - log_id_t log_id = LOG_ID_MAIN; - char tmp_tag[32]; - - if (!tag) - tag = ""; - - /* XXX: This needs to go! */ - if (!strcmp(tag, "HTC_RIL") || - !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ - !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ - !strcmp(tag, "AT") || - !strcmp(tag, "GSM") || - !strcmp(tag, "STK") || - !strcmp(tag, "CDMA") || - !strcmp(tag, "PHONE") || - !strcmp(tag, "SMS")) { - log_id = LOG_ID_RADIO; - /* Inform third party apps/ril/radio.. to use Rlog or RLOG */ - snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); - tag = tmp_tag; - } - -#if __BIONIC__ - if (prio == ANDROID_LOG_FATAL) { - android_set_abort_message(msg); - } -#endif - - vec[0].iov_base = (unsigned char *) &prio; - vec[0].iov_len = 1; - vec[1].iov_base = (void *) tag; - vec[1].iov_len = strlen(tag) + 1; - vec[2].iov_base = (void *) msg; - vec[2].iov_len = strlen(msg) + 1; - - return write_to_log(log_id, vec, 3); + return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg); } int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg) @@ -420,6 +384,12 @@ int __android_log_buf_write(int bufID, int prio, const char *tag, const char *ms tag = tmp_tag; } +#if __BIONIC__ + if (prio == ANDROID_LOG_FATAL) { + android_set_abort_message(msg); + } +#endif + vec[0].iov_base = (unsigned char *) &prio; vec[0].iov_len = 1; vec[1].iov_base = (void *) tag; diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c index ca63067..8742b34 100644 --- a/liblog/logd_write_kern.c +++ b/liblog/logd_write_kern.c @@ -139,41 +139,7 @@ static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) int __android_log_write(int prio, const char *tag, const char *msg) { - struct iovec vec[3]; - log_id_t log_id = LOG_ID_MAIN; - char tmp_tag[32]; - - if (!tag) - tag = ""; - - /* XXX: This needs to go! */ - if (!strcmp(tag, "HTC_RIL") || - !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ - !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */ - !strcmp(tag, "AT") || - !strcmp(tag, "GSM") || - !strcmp(tag, "STK") || - !strcmp(tag, "CDMA") || - !strcmp(tag, "PHONE") || - !strcmp(tag, "SMS")) { - log_id = LOG_ID_RADIO; - /* Inform third party apps/ril/radio.. to use Rlog or RLOG */ - snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); - tag = tmp_tag; - } - - if (prio == ANDROID_LOG_FATAL) { - android_set_abort_message(msg); - } - - vec[0].iov_base = (unsigned char *) &prio; - vec[0].iov_len = 1; - vec[1].iov_base = (void *) tag; - vec[1].iov_len = strlen(tag) + 1; - vec[2].iov_base = (void *) msg; - vec[2].iov_len = strlen(msg) + 1; - - return write_to_log(log_id, vec, 3); + return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg); } int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg) @@ -201,6 +167,10 @@ int __android_log_buf_write(int bufID, int prio, const char *tag, const char *ms tag = tmp_tag; } + if (prio == ANDROID_LOG_FATAL) { + android_set_abort_message(msg); + } + vec[0].iov_base = (unsigned char *) &prio; vec[0].iov_len = 1; vec[1].iov_base = (void *) tag; diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk index 8137a75..d75bbc9 100644 --- a/liblog/tests/Android.mk +++ b/liblog/tests/Android.mk @@ -39,7 +39,6 @@ benchmark_src_files := \ include $(CLEAR_VARS) LOCAL_MODULE := $(test_module_prefix)benchmarks LOCAL_MODULE_TAGS := $(test_tags) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += $(benchmark_c_flags) LOCAL_SHARED_LIBRARIES += liblog libm LOCAL_SRC_FILES := $(benchmark_src_files) @@ -77,7 +76,6 @@ endif include $(CLEAR_VARS) LOCAL_MODULE := $(test_module_prefix)unit-tests LOCAL_MODULE_TAGS := $(test_tags) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += $(test_c_flags) LOCAL_SHARED_LIBRARIES := liblog LOCAL_SRC_FILES := $(test_src_files) diff --git a/libsparse/append2simg.c b/libsparse/append2simg.c index 65e6cc2..1cf827c 100644 --- a/libsparse/append2simg.c +++ b/libsparse/append2simg.c @@ -82,7 +82,7 @@ int main(int argc, char *argv[]) exit(-1); } - sparse_output = sparse_file_import_auto(output, true); + sparse_output = sparse_file_import_auto(output, true, true); if (!sparse_output) { fprintf(stderr, "Couldn't import output file\n"); exit(-1); diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h index 8b757d2..42d4adb 100644 --- a/libsparse/include/sparse/sparse.h +++ b/libsparse/include/sparse/sparse.h @@ -234,6 +234,7 @@ struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc); * * @fd - file descriptor to read from * @crc - verify the crc of a file in the Android sparse file format + * @verbose - whether to use verbose logging * * Reads an existing sparse or normal file into a sparse file cookie. * Attempts to determine if the file is sparse or not by looking for the sparse @@ -243,7 +244,7 @@ struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc); * * Returns a new sparse file cookie on success, NULL on error. */ -struct sparse_file *sparse_file_import_auto(int fd, bool crc); +struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose); /** sparse_file_resparse - rechunk an existing sparse file into smaller files * diff --git a/libsparse/sparse_read.c b/libsparse/sparse_read.c index 8e188e9..9b10293 100644 --- a/libsparse/sparse_read.c +++ b/libsparse/sparse_read.c @@ -472,13 +472,13 @@ struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc) return s; } -struct sparse_file *sparse_file_import_auto(int fd, bool crc) +struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose) { struct sparse_file *s; int64_t len; int ret; - s = sparse_file_import(fd, true, crc); + s = sparse_file_import(fd, verbose, crc); if (s) { return s; } diff --git a/libsync/tests/Android.mk b/libsync/tests/Android.mk index 9c9562a..8137c7a 100644 --- a/libsync/tests/Android.mk +++ b/libsync/tests/Android.mk @@ -19,7 +19,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_MODULE := sync-unit-tests -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers -Wno-sign-compare LOCAL_SHARED_LIBRARIES += libsync LOCAL_STATIC_LIBRARIES += libgtest_main diff --git a/libutils/tests/Android.mk b/libutils/tests/Android.mk index 634f44f..7cfad89 100644 --- a/libutils/tests/Android.mk +++ b/libutils/tests/Android.mk @@ -18,7 +18,6 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := libutils_tests diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk index 3937449..0d31001 100644 --- a/libziparchive/Android.mk +++ b/libziparchive/Android.mk @@ -18,7 +18,6 @@ LOCAL_PATH := $(call my-dir) source_files := zip_archive.cc include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CPP_EXTENSION := .cc LOCAL_SRC_FILES := ${source_files} LOCAL_STATIC_LIBRARIES := libz @@ -29,7 +28,6 @@ LOCAL_CPPFLAGS := -Wold-style-cast include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CPP_EXTENSION := .cc LOCAL_SRC_FILES := ${source_files} LOCAL_STATIC_LIBRARIES := libz libutils @@ -42,7 +40,6 @@ LOCAL_MULTILIB := both include $(BUILD_HOST_STATIC_LIBRARY) include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CPP_EXTENSION := .cc LOCAL_SRC_FILES := ${source_files} LOCAL_STATIC_LIBRARIES := libz libutils @@ -54,7 +51,6 @@ include $(BUILD_HOST_SHARED_LIBRARY) # Tests. include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := ziparchive-tests LOCAL_CPP_EXTENSION := .cc LOCAL_CFLAGS := -Werror @@ -64,7 +60,6 @@ LOCAL_STATIC_LIBRARIES := libziparchive libz libutils include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := ziparchive-tests-host LOCAL_CPP_EXTENSION := .cc LOCAL_CFLAGS += \ diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk index 015a23d..a28664e 100644 --- a/logcat/tests/Android.mk +++ b/logcat/tests/Android.mk @@ -39,7 +39,6 @@ benchmark_src_files := \ include $(CLEAR_VARS) LOCAL_MODULE := $(test_module_prefix)benchmarks LOCAL_MODULE_TAGS := $(test_tags) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += $(test_c_flags) LOCAL_SRC_FILES := $(benchmark_src_files) include $(BUILD_NATIVE_TEST) @@ -56,7 +55,6 @@ test_src_files := \ include $(CLEAR_VARS) LOCAL_MODULE := $(test_module_prefix)unit-tests LOCAL_MODULE_TAGS := $(test_tags) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += $(test_c_flags) LOCAL_SHARED_LIBRARIES := liblog LOCAL_SRC_FILES := $(test_src_files) diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp index e4c138e..b78c0e0 100644 --- a/logd/LogCommand.cpp +++ b/logd/LogCommand.cpp @@ -17,6 +17,7 @@ #include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <private/android_filesystem_config.h> diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk index f851288..85ca4ac 100644 --- a/logd/tests/Android.mk +++ b/logd/tests/Android.mk @@ -46,7 +46,6 @@ test_src_files := \ include $(CLEAR_VARS) LOCAL_MODULE := $(test_module_prefix)unit-tests LOCAL_MODULE_TAGS := $(test_tags) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += $(test_c_flags) LOCAL_SHARED_LIBRARIES := libcutils LOCAL_SRC_FILES := $(test_src_files) diff --git a/rootdir/init.rc b/rootdir/init.rc index 3ae0954..cda79ce 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -225,6 +225,8 @@ on post-fs mkdir /cache/lost+found 0770 root root on post-fs-data + installkey /data + # We chown/chmod /data again so because mount is run as root + defaults chown system system /data chmod 0771 /data @@ -303,6 +305,14 @@ on post-fs-data # Separate location for storing security policy files on data mkdir /data/security 0711 system system + # Create all remaining /data root dirs so that they are made through init + # and get proper encryption policy installed + mkdir /data/backup 0700 system system + mkdir /data/media 0770 media_rw media_rw + mkdir /data/ss 0700 system system + mkdir /data/system 0775 system system + mkdir /data/user 0711 system system + # Reload policy from /data/security if present. setprop selinux.reload_policy 1 @@ -438,6 +448,7 @@ on property:vold.decrypt=trigger_restart_min_framework class_start main on property:vold.decrypt=trigger_restart_framework + installkey /data class_start main class_start late_start diff --git a/run-as/package.c b/run-as/package.c index 4f8f3a7..9e1f5bb 100644 --- a/run-as/package.c +++ b/run-as/package.c @@ -16,9 +16,11 @@ */ #include <errno.h> #include <fcntl.h> -#include <unistd.h> -#include <sys/stat.h> +#include <string.h> #include <sys/mman.h> +#include <sys/stat.h> +#include <unistd.h> + #include <private/android_filesystem_config.h> #include "package.h" diff --git a/run-as/run-as.c b/run-as/run-as.c index cc05e63..368b8f1 100644 --- a/run-as/run-as.c +++ b/run-as/run-as.c @@ -15,22 +15,25 @@ ** limitations under the License. */ -#define PROGNAME "run-as" -#define LOG_TAG PROGNAME +#define PROGNAME "run-as" +#define LOG_TAG PROGNAME +#include <dirent.h> +#include <errno.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/types.h> +#include <sys/capability.h> +#include <sys/cdefs.h> #include <sys/stat.h> -#include <dirent.h> -#include <errno.h> -#include <unistd.h> +#include <sys/types.h> #include <time.h> -#include <stdarg.h> +#include <unistd.h> -#include <selinux/android.h> #include <private/android_filesystem_config.h> +#include <selinux/android.h> + #include "package.h" /* @@ -83,37 +86,37 @@ * - Run the 'gdbserver' binary executable to allow native debugging */ -static void -usage(void) -{ - const char* str = "Usage: " PROGNAME " <package-name> <command> [<args>]\n\n"; - write(1, str, strlen(str)); - exit(1); -} - - -static void +__noreturn static void panic(const char* format, ...) { va_list args; + int e = errno; fprintf(stderr, "%s: ", PROGNAME); va_start(args, format); vfprintf(stderr, format, args); va_end(args); - exit(1); + exit(e ? -e : 1); } +static void +usage(void) +{ + panic("Usage:\n " PROGNAME " <package-name> <command> [<args>]\n"); +} int main(int argc, char **argv) { const char* pkgname; int myuid, uid, gid; PackageInfo info; + struct __user_cap_header_struct capheader; + struct __user_cap_data_struct capdata[2]; /* check arguments */ - if (argc < 2) + if (argc < 2) { usage(); + } /* check userid of caller - must be 'shell' or 'root' */ myuid = getuid(); @@ -121,29 +124,37 @@ int main(int argc, char **argv) panic("only 'shell' or 'root' users can run this program\n"); } - /* retrieve package information from system */ + memset(&capheader, 0, sizeof(capheader)); + memset(&capdata, 0, sizeof(capdata)); + capheader.version = _LINUX_CAPABILITY_VERSION_3; + capdata[CAP_TO_INDEX(CAP_SETUID)].effective |= CAP_TO_MASK(CAP_SETUID); + capdata[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID); + capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID); + capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID); + + if (capset(&capheader, &capdata[0]) < 0) { + panic("Could not set capabilities: %s\n", strerror(errno)); + } + + /* retrieve package information from system (does setegid) */ pkgname = argv[1]; if (get_package_info(pkgname, &info) < 0) { panic("Package '%s' is unknown\n", pkgname); - return 1; } /* reject system packages */ if (info.uid < AID_APP) { panic("Package '%s' is not an application\n", pkgname); - return 1; } /* reject any non-debuggable package */ if (!info.isDebuggable) { panic("Package '%s' is not debuggable\n", pkgname); - return 1; } /* check that the data directory path is valid */ if (check_data_path(info.dataDir, info.uid) < 0) { panic("Package '%s' has corrupt installation\n", pkgname); - return 1; } /* Ensure that we change all real/effective/saved IDs at the @@ -152,38 +163,30 @@ int main(int argc, char **argv) uid = gid = info.uid; if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) { panic("Permission denied\n"); - return 1; + } + + /* Required if caller has uid and gid all non-zero */ + memset(&capdata, 0, sizeof(capdata)); + if (capset(&capheader, &capdata[0]) < 0) { + panic("Could not clear all capabilities: %s\n", strerror(errno)); } if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) { - panic("Could not set SELinux security context: %s\n", strerror(errno)); - return 1; + panic("Could not set SELinux security context: %s\n", strerror(errno)); } /* cd into the data directory */ - { - int ret; - do { - ret = chdir(info.dataDir); - } while (ret < 0 && errno == EINTR); - - if (ret < 0) { - panic("Could not cd to package's data directory: %s\n", strerror(errno)); - return 1; - } + if (TEMP_FAILURE_RETRY(chdir(info.dataDir)) < 0) { + panic("Could not cd to package's data directory: %s\n", strerror(errno)); } /* User specified command for exec. */ - if (argc >= 3 ) { - if (execvp(argv[2], argv+2) < 0) { - panic("exec failed for %s Error:%s\n", argv[2], strerror(errno)); - return -errno; - } + if ((argc >= 3) && (execvp(argv[2], argv+2) < 0)) { + panic("exec failed for %s: %s\n", argv[2], strerror(errno)); } /* Default exec shell. */ execlp("/system/bin/sh", "sh", NULL); - panic("exec failed\n"); - return 1; + panic("exec failed: %s\n", strerror(errno)); } diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 4d50bf0..041c37a 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -199,6 +199,8 @@ struct node { * position. Used to support things like OBB. */ char* graft_path; size_t graft_pathlen; + + bool deleted; }; static int str_hash(void *key) { @@ -631,6 +633,8 @@ struct node *create_node_locked(struct fuse* fuse, node->ino = fuse->inode_ctr++; node->gen = fuse->next_generation++; + node->deleted = false; + derive_permissions_locked(fuse, parent, node); acquire_node_locked(node); add_node_to_parent_locked(node, parent); @@ -704,7 +708,7 @@ static struct node *lookup_child_by_name_locked(struct node *node, const char *n * must be considered distinct even if they refer to the same * underlying file as otherwise operations such as "mv x x" * will not work because the source and target nodes are the same. */ - if (!strcmp(name, node->name)) { + if (!strcmp(name, node->name) && !node->deleted) { return node; } } @@ -1070,6 +1074,7 @@ static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler, { bool has_rw; struct node* parent_node; + struct node* child_node; char parent_path[PATH_MAX]; char child_path[PATH_MAX]; @@ -1091,6 +1096,12 @@ static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler, if (unlink(child_path) < 0) { return -errno; } + pthread_mutex_lock(&fuse->lock); + child_node = lookup_child_by_name_locked(parent_node, name); + if (child_node) { + child_node->deleted = true; + } + pthread_mutex_unlock(&fuse->lock); return 0; } @@ -1098,6 +1109,7 @@ static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler, const struct fuse_in_header* hdr, const char* name) { bool has_rw; + struct node* child_node; struct node* parent_node; char parent_path[PATH_MAX]; char child_path[PATH_MAX]; @@ -1120,6 +1132,12 @@ static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler, if (rmdir(child_path) < 0) { return -errno; } + pthread_mutex_lock(&fuse->lock); + child_node = lookup_child_by_name_locked(parent_node, name); + if (child_node) { + child_node->deleted = true; + } + pthread_mutex_unlock(&fuse->lock); return 0; } @@ -1869,7 +1887,8 @@ static int run(const char* source_path, const char* dest_path, uid_t uid, "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d", fd, uid, gid); - res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC, opts); + res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC | + MS_NOATIME, opts); if (res < 0) { ERROR("cannot mount fuse filesystem: %s\n", strerror(errno)); goto error; diff --git a/toolbox/Android.mk b/toolbox/Android.mk index 4e54eb8..186a89f 100644 --- a/toolbox/Android.mk +++ b/toolbox/Android.mk @@ -23,14 +23,12 @@ LOCAL_SRC_FILES := \ upstream-netbsd/lib/libutil/raise_default_signal.c LOCAL_CFLAGS += $(common_cflags) -Dmain=dd_main -DNO_CONV LOCAL_MODULE := libtoolbox_dd -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_SRC_FILES := upstream-netbsd/usr.bin/du/du.c LOCAL_CFLAGS += $(common_cflags) -Dmain=du_main LOCAL_MODULE := libtoolbox_du -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk include $(BUILD_STATIC_LIBRARY) @@ -62,7 +60,6 @@ OUR_TOOLS := \ start \ stop \ top \ - umount \ uptime \ watchprops \ @@ -82,7 +79,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_WHOLE_STATIC_LIBRARIES := $(patsubst %,libtoolbox_%,$(BSD_TOOLS)) LOCAL_MODULE := toolbox -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk # Install the symlinks. LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(ALL_TOOLS),ln -sf toolbox $(TARGET_OUT)/bin/$(t);) @@ -115,7 +111,6 @@ LOCAL_SRC_FILES := r.c LOCAL_CFLAGS += $(common_cflags) LOCAL_MODULE := r LOCAL_MODULE_TAGS := debug -LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk include $(BUILD_EXECUTABLE) diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c index d1cc14a..093e467 100644 --- a/toolbox/ioctl.c +++ b/toolbox/ioctl.c @@ -1,36 +1,81 @@ -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> +/* + * Copyright (c) 2008, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <errno.h> +#include <error.h> #include <fcntl.h> #include <getopt.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> #include <string.h> -#include <linux/kd.h> -#include <linux/vt.h> -#include <errno.h> -#include <pthread.h> #include <sys/ioctl.h> #include <unistd.h> -int ioctl_main(int argc, char *argv[]) -{ - int c; - int fd; - int res; +static void usage() { + fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n" + " -l <length> Length of io buffer\n" + " -a <argsize> Size of each argument (1-8)\n" + " -r Open device in read only mode\n" + " -d Direct argument (no iobuffer)\n" + " -h Print help\n", getprogname()); + exit(1); +} + +static int xstrtoi(const char* s, const char* what) { + char* endp; + errno = 0; + long result = strtol(s, &endp, 0); + if (errno != 0 || *endp != '\0') { + error(1, errno, "couldn't parse %s '%s'", what, s); + } + if (result > INT_MAX || result < INT_MIN) { + error(1, errno, "%s '%s' out of range", what, s); + } + return result; +} +int ioctl_main(int argc, char* argv[]) { int read_only = 0; int length = -1; int arg_size = 4; int direct_arg = 0; - uint32_t ioctl_nr; + void *ioctl_args = NULL; uint8_t *ioctl_argp; uint8_t *ioctl_argp_save = NULL; int rem; - do { - c = getopt(argc, argv, "rdl:a:h"); - if (c == EOF) - break; + int c; + while ((c = getopt(argc, argv, "rdl:a:h")) != -1) { switch (c) { case 'r': read_only = 1; @@ -39,43 +84,44 @@ int ioctl_main(int argc, char *argv[]) direct_arg = 1; break; case 'l': - length = strtol(optarg, NULL, 0); + length = xstrtoi(optarg, "length"); break; case 'a': - arg_size = strtol(optarg, NULL, 0); + arg_size = xstrtoi(optarg, "argument size"); break; case 'h': - fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n" - " -l <length> Length of io buffer\n" - " -a <argsize> Size of each argument (1-8)\n" - " -r Open device in read only mode\n" - " -d Direct argument (no iobuffer)\n" - " -h Print help\n", argv[0]); - return -1; - case '?': - fprintf(stderr, "%s: invalid option -%c\n", - argv[0], optopt); - exit(1); + usage(); + break; + default: + error(1, 0, "invalid option -%c", optopt); } - } while (1); + } - if(optind + 2 > argc) { - fprintf(stderr, "%s: too few arguments\n", argv[0]); - exit(1); + if (optind + 2 > argc) { + usage(); } - if (!strcmp(argv[optind], "-")) { + const char* device = argv[optind]; + int fd; + if (strcmp(device, "-") == 0) { fd = STDIN_FILENO; } else { - fd = open(argv[optind], read_only ? O_RDONLY : (O_RDWR | O_SYNC)); - if (fd < 0) { - fprintf(stderr, "cannot open %s\n", argv[optind]); - return 1; + fd = open(device, read_only ? O_RDONLY : (O_RDWR | O_SYNC)); + if (fd == -1) { + error(1, errno, "cannot open %s", argv[optind]); } } optind++; - - ioctl_nr = strtol(argv[optind], NULL, 0); + + // IOCTL(2) wants second parameter as a signed int. + // Let's let the user specify either negative numbers or large positive + // numbers, for the case where ioctl number is larger than INT_MAX. + errno = 0; + char* endp; + int ioctl_nr = UINT_MAX & strtoll(argv[optind], &endp, 0); + if (errno != 0 || *endp != '\0') { + error(1, errno, "couldn't parse ioctl number '%s'", argv[optind]); + } optind++; if(direct_arg) { @@ -91,11 +137,10 @@ int ioctl_main(int argc, char *argv[]) ioctl_argp_save = ioctl_argp = ioctl_args; rem = length; - while(optind < argc) { + while (optind < argc) { uint64_t tmp = strtoull(argv[optind], NULL, 0); - if(rem < arg_size) { - fprintf(stderr, "%s: too many arguments\n", argv[0]); - exit(1); + if (rem < arg_size) { + error(1, 0, "too many arguments"); } memcpy(ioctl_argp, &tmp, arg_size); ioctl_argp += arg_size; @@ -108,8 +153,9 @@ int ioctl_main(int argc, char *argv[]) while(rem--) { printf(" 0x%02x", *ioctl_argp_save++); } - printf("\n"); + printf(" to %s\n", device); + int res; if(direct_arg) res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args); else if(length) @@ -118,10 +164,10 @@ int ioctl_main(int argc, char *argv[]) res = ioctl(fd, ioctl_nr, 0); if (res < 0) { free(ioctl_args); - fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res); - return 1; + error(1, errno, "ioctl 0x%x failed (returned %d)", ioctl_nr, res); } - if(length) { + + if (length) { printf("return buf:"); ioctl_argp = ioctl_args; rem = length; @@ -131,5 +177,6 @@ int ioctl_main(int argc, char *argv[]) printf("\n"); } free(ioctl_args); + close(fd); return 0; } diff --git a/toolbox/umount.c b/toolbox/umount.c deleted file mode 100644 index 3e17396..0000000 --- a/toolbox/umount.c +++ /dev/null @@ -1,90 +0,0 @@ - -#include <sys/mount.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <linux/loop.h> -#include <errno.h> - -#define LOOPDEV_MAXLEN 64 -#define LOOP_MAJOR 7 - -static int is_loop(char *dev) -{ - struct stat st; - int ret = 0; - - if (stat(dev, &st) == 0) { - if (S_ISBLK(st.st_mode) && (major(st.st_rdev) == LOOP_MAJOR)) { - ret = 1; - } - } - - return ret; -} - -static int is_loop_mount(const char* path, char *loopdev) -{ - FILE* f; - int count; - char device[256]; - char mount_path[256]; - char rest[256]; - int result = 0; - - f = fopen("/proc/mounts", "r"); - if (!f) { - fprintf(stdout, "could not open /proc/mounts: %s\n", strerror(errno)); - return -1; - } - - do { - count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest); - if (count == 3) { - if (is_loop(device) && strcmp(path, mount_path) == 0) { - strlcpy(loopdev, device, LOOPDEV_MAXLEN); - result = 1; - break; - } - } - } while (count == 3); - - fclose(f); - return result; -} - -int umount_main(int argc, char *argv[]) -{ - int loop, loop_fd; - char loopdev[LOOPDEV_MAXLEN]; - - if(argc != 2) { - fprintf(stderr,"umount <path>\n"); - return 1; - } - - loop = is_loop_mount(argv[1], loopdev); - if (umount(argv[1])) { - fprintf(stderr, "failed: %s\n", strerror(errno)); - return 1; - } - - if (loop) { - // free the loop device - loop_fd = open(loopdev, O_RDONLY); - if (loop_fd < 0) { - fprintf(stderr, "open loop device failed: %s\n", strerror(errno)); - return 1; - } - if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) { - fprintf(stderr, "ioctl LOOP_CLR_FD failed: %s\n", strerror(errno)); - return 1; - } - - close(loop_fd); - } - - return 0; -} |