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: I46ba2dd67c188be74bd931f8a5536b6342d537f2
This commit is contained in:
Josh Gao 2017-03-28 13:07:15 -07:00 committed by Tom Cherry
parent 6b6c2f1efb
commit 3e76ecaf80
3 changed files with 56 additions and 1 deletions

View file

@ -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) {

View file

@ -9,12 +9,14 @@ init_options += \
-DALLOW_LOCAL_PROP_OVERRIDE=1 \
-DALLOW_PERMISSIVE_SELINUX=1 \
-DREBOOT_BOOTLOADER_ON_PANIC=1 \
-DWORLD_WRITABLE_KMSG=1 \
-DDUMP_ON_UMOUNT_FAILURE=1
else
init_options += \
-DALLOW_LOCAL_PROP_OVERRIDE=0 \
-DALLOW_PERMISSIVE_SELINUX=0 \
-DREBOOT_BOOTLOADER_ON_PANIC=0 \
-DWORLD_WRITABLE_KMSG=0 \
-DDUMP_ON_UMOUNT_FAILURE=0
endif

View file

@ -933,6 +933,9 @@ static void selinux_restore_context() {
LOG(INFO) << "Running restorecon...";
selinux_android_restorecon("/dev", 0);
selinux_android_restorecon("/dev/kmsg", 0);
if constexpr (WORLD_WRITABLE_KMSG) {
selinux_android_restorecon("/dev/kmsg_debug", 0);
}
selinux_android_restorecon("/dev/socket", 0);
selinux_android_restorecon("/dev/random", 0);
selinux_android_restorecon("/dev/urandom", 0);
@ -1037,7 +1040,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));