summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Gao <jmgao@google.com>2017-03-28 13:07:15 -0700
committerJosh Gao <jmgao@google.com>2017-04-06 15:00:52 -0700
commitbf2dd482412cb7b93f52d2ed2d9be9a32fa8d2f9 (patch)
tree13e597ec30c32adb760606ef1ddb99bc0a989aa4
parentebc87c98e35327e7403ed767c935a8e6a02b6f03 (diff)
downloadcore-bf2dd482412cb7b93f52d2ed2d9be9a32fa8d2f9.tar.gz
core-bf2dd482412cb7b93f52d2ed2d9be9a32fa8d2f9.tar.bz2
core-bf2dd482412cb7b93f52d2ed2d9be9a32fa8d2f9.zip
crash_dump: during early boot, output to kmsg on userdebug.
Crashes that happen before tombstoned is running are extremely hard to diagnose, because tombstones aren't written to disk, and the window of opportunity to get logs via `adb logcat` is small (potentially nonexistent). Solve this by adding a world-writable /dev/kmsg_debug on userdebug builds, and writing to it in addition to logcat when tombstoned hasn't started yet. Bug: http://b/36574794 Test: stop tombstoned; crasher; dmesg Change-Id: Ib22c02a002afb602933155fb2c9b7a8abbe9ed38
-rw-r--r--debuggerd/libdebuggerd/utility.cpp46
-rw-r--r--init/Android.mk6
-rw-r--r--init/init.cpp9
3 files changed, 58 insertions, 3 deletions
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 22fde5ea4..7f450e6bc 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -22,16 +22,22 @@
#include <signal.h>
#include <string.h>
#include <sys/ptrace.h>
+#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <backtrace/Backtrace.h>
#include <log/log.h>
+using android::base::unique_fd;
+
// Whitelist output desired in the logcat output.
bool is_allowed_in_logcat(enum logtype ltype) {
if ((ltype == HEADER)
@@ -42,6 +48,19 @@ bool is_allowed_in_logcat(enum logtype ltype) {
return false;
}
+static bool should_write_to_kmsg() {
+ // Write to kmsg if tombstoned isn't up, and we're able to do so.
+ if (!android::base::GetBoolProperty("ro.debuggable", false)) {
+ return false;
+ }
+
+ if (android::base::GetProperty("init.svc.tombstoned", "") == "running") {
+ return false;
+ }
+
+ return true;
+}
+
__attribute__((__weak__, visibility("default")))
void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
bool write_to_tombstone = (log->tfd != -1);
@@ -49,6 +68,7 @@ void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
&& log->crashed_tid != -1
&& log->current_tid != -1
&& (log->crashed_tid == log->current_tid);
+ static bool write_to_kmsg = should_write_to_kmsg();
char buf[512];
va_list ap;
@@ -70,6 +90,30 @@ void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
if (log->amfd_data != nullptr) {
*log->amfd_data += buf;
}
+
+ if (write_to_kmsg) {
+ unique_fd kmsg_fd(open("/dev/kmsg_debug", O_WRONLY | O_APPEND | O_CLOEXEC));
+ if (kmsg_fd.get() >= 0) {
+ // Our output might contain newlines which would otherwise be handled by the android logger.
+ // Split the lines up ourselves before sending to the kernel logger.
+ if (buf[len - 1] == '\n') {
+ buf[len - 1] = '\0';
+ }
+
+ std::vector<std::string> fragments = android::base::Split(buf, "\n");
+ for (const std::string& fragment : fragments) {
+ static constexpr char prefix[] = "<3>DEBUG: ";
+ struct iovec iov[3];
+ iov[0].iov_base = const_cast<char*>(prefix);
+ iov[0].iov_len = strlen(prefix);
+ iov[1].iov_base = const_cast<char*>(fragment.c_str());
+ iov[1].iov_len = fragment.length();
+ iov[2].iov_base = const_cast<char*>("\n");
+ iov[2].iov_len = 1;
+ TEMP_FAILURE_RETRY(writev(kmsg_fd.get(), iov, 3));
+ }
+ }
+ }
}
}
@@ -205,7 +249,7 @@ void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* f
}
void read_with_default(const char* path, char* buf, size_t len, const char* default_value) {
- android::base::unique_fd fd(open(path, O_RDONLY));
+ unique_fd fd(open(path, O_RDONLY | O_CLOEXEC));
if (fd != -1) {
int rc = TEMP_FAILURE_RETRY(read(fd.get(), buf, len - 1));
if (rc != -1) {
diff --git a/init/Android.mk b/init/Android.mk
index 1ca88d7c5..61c2ec8f1 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -8,12 +8,14 @@ ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
init_options += \
-DALLOW_LOCAL_PROP_OVERRIDE=1 \
-DALLOW_PERMISSIVE_SELINUX=1 \
- -DREBOOT_BOOTLOADER_ON_PANIC=1
+ -DREBOOT_BOOTLOADER_ON_PANIC=1 \
+ -DWORLD_WRITABLE_KMSG=1
else
init_options += \
-DALLOW_LOCAL_PROP_OVERRIDE=0 \
-DALLOW_PERMISSIVE_SELINUX=0 \
- -DREBOOT_BOOTLOADER_ON_PANIC=0
+ -DREBOOT_BOOTLOADER_ON_PANIC=0 \
+ -DWORLD_WRITABLE_KMSG=0
endif
ifneq (,$(filter eng,$(TARGET_BUILD_VARIANT)))
diff --git a/init/init.cpp b/init/init.cpp
index e14034f6f..9ca41fafb 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -884,6 +884,9 @@ static void selinux_restore_context() {
LOG(INFO) << "Running restorecon...";
restorecon("/dev");
restorecon("/dev/kmsg");
+ if constexpr (WORLD_WRITABLE_KMSG) {
+ restorecon("/dev/kmsg_debug");
+ }
restorecon("/dev/socket");
restorecon("/dev/random");
restorecon("/dev/urandom");
@@ -1160,7 +1163,13 @@ int main(int argc, char** argv) {
setgroups(arraysize(groups), groups);
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
+
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
+
+ if constexpr (WORLD_WRITABLE_KMSG) {
+ mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11));
+ }
+
mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));