在Logcat中增加kernel打印

来源:互联网 发布:大数据迁移 编辑:程序博客网 时间:2024/06/15 15:36


1 Logcat 的原理简介

Logcat的打印类型有eventsradiosystemmain等几项,执行命令如下:

Logcat –b events/radio/system/main

 

其原理主要是打开/dev/log/events/dev/log/radio, /dev/log/system, /dev/log/main等设备文件,读取该文件的数据,再对数据进行解析后打印出来。

2 logcat 设备文件的存储格式

设备文件里的打印是按如下格式存储的:

prioTAG’\0’msg’\0’

 

prio 是一个整型,值为0~8,对应的优化级别如下:

typedef enum android_LogPriority {

   ANDROID_LOG_UNKNOWN = 0,

   ANDROID_LOG_DEFAULT,    /* onlyfor SetMinPriority() */

   ANDROID_LOG_VERBOSE,

   ANDROID_LOG_DEBUG,

   ANDROID_LOG_INFO,

   ANDROID_LOG_WARN,

   ANDROID_LOG_ERROR,

   ANDROID_LOG_FATAL,

   ANDROID_LOG_SILENT,     /* onlyfor SetMinPriority(); must be last */

} android_LogPriority;

 

TAG是一个标签,字符串类型,在本文中定义为“KERNEL”,以表示内核打印。

 

Msg 是打印的字符串,本文中该字符串由printk函数里获得,以达到与内核打印一致。

3本文功能实现的思路

printk中的字符串,按logcat所需的格式存储到/dev/log/kernel设备文件里,然后就可以通过logcat –b kernel将内核信息打印出来。

 

4本文功能的好处

可通过adb logcat 将内核进行实时同步打印,改善dmesg命令不能实现实时打印缺陷。

 

5 本文功能的实现

 

Index: drivers/staging/android/logger.c

===================================================================

--- drivers/staging/android/logger.c    (版本 13)

+++ drivers/staging/android/logger.c    (工作副本)

@@ -316,6 +316,7 @@

       return count;

 }

 

+

 /*

  *logger_aio_write - our write method, implementing support for write(),

  *writev(), and aio_write(). Writes are our fast path, and we try to optimize

@@ -372,7 +373,6 @@

                iov++;

                ret += nr;

       }

-

       mutex_unlock(&log->mutex);

 

       /* wake up any blocked readers */

@@ -559,6 +559,7 @@

 DEFINE_LOGGER_DEVICE(log_events,LOGGER_LOG_EVENTS, 256*1024)

 DEFINE_LOGGER_DEVICE(log_radio,LOGGER_LOG_RADIO, 256*1024)

 DEFINE_LOGGER_DEVICE(log_system,LOGGER_LOG_SYSTEM, 256*1024)

+DEFINE_LOGGER_DEVICE(log_kernel,LOGGER_LOG_KERNEL, 256*1024)

 

 static struct logger_log *get_log_from_minor(intminor)

 {

@@ -570,9 +571,73 @@

                return &log_radio;

       if (log_system.misc.minor == minor)

                return &log_system;

+      if (log_kernel.misc.minor == minor)

+               return &log_kernel;

       return NULL;

 }

 

+ssize_t logger_write_ext(const char *buf,unsigned long count)

+{

+      struct logger_log *log = &log_kernel;

+      size_t orig = log->w_off;

+      struct logger_entry header;

+      struct timespec now;

+      ssize_t nr = 0;

+      int prio = 3;

+      char tag[7] = {'K','E','R','N','E','L','\0'};

+

+      now = current_kernel_time();

+

+      header.pid = current->tgid;

+      header.tid = current->pid;

+      header.sec = now.tv_sec;

+      header.nsec = now.tv_nsec;

+      header.len = min_t(size_t, count+8, LOGGER_ENTRY_MAX_PAYLOAD);

+

+      /* null writes succeed, return zero */

+      if (count == 0)

+               return 0;

+

+      mutex_lock(&log->mutex);

+

+      /*

+       * Fix up any readers, pulling them forward to the first readable

+       * entry after (what will be) the new write offset. We do this now

+       * because if we partially fail, we can end up with clobbered log

+       * entries that encroach on readable buffer.

+       */

+      fix_up_readers(log, sizeof(struct logger_entry) + header.len);

+

+      do_write_log(log, &header, sizeof(struct logger_entry));

+

+      nr = do_write_log_from_user(log, &prio, 1);

+      if (unlikely(nr < 0)) {

+               log->w_off = orig;

+              mutex_unlock(&log->mutex);

+               return nr;

+      }

+

+      nr = do_write_log_from_user(log, tag, 7);

+      if (unlikely(nr < 0)) {

+               log->w_off = orig;

+              mutex_unlock(&log->mutex);

+               return nr;

+      }

+

+      nr = do_write_log_from_user(log, buf, count);

+      if (unlikely(nr < 0)) {

+               log->w_off = orig;

+              mutex_unlock(&log->mutex);

+               return nr;

+      }

+

+      mutex_unlock(&log->mutex);

+

+       /* wake up any blocked readers */

+      wake_up_interruptible(&log->wq);

+

+      return nr;

+}

 static int __init init_log(struct logger_log*log)

 {

       int ret;

@@ -610,6 +675,10 @@

       if (unlikely(ret))

                goto out;

 

+       ret = init_log(&log_kernel);

+      if (unlikely(ret))

+               goto out;

+

 out:

       return ret;

 }

 

Index: drivers/staging/android/logger.h

===================================================================

--- drivers/staging/android/logger.h    (版本 13)

+++ drivers/staging/android/logger.h    (工作副本)

@@ -34,6 +34,7 @@

 #define LOGGER_LOG_EVENTS      "log_events"    /* system/hardware events */

 #define LOGGER_LOG_SYSTEM      "log_system"    /* system/framework messages */

 #define LOGGER_LOG_MAIN                "log_main"      /* everything else */

+#define LOGGER_LOG_KERNEL              "log_kernel"    /* kernel */

 

 #define LOGGER_ENTRY_MAX_LEN           (4*1024)

 #define LOGGER_ENTRY_MAX_PAYLOAD       \

 

 

Index: kernel/printk.c

===================================================================

--- kernel/printk.c     (版本 13)

+++ kernel/printk.c     (工作副本)

@@ -784,11 +784,15 @@

  *See the vsnprintf() documentation for format string extensions over C99.

  */

 

+extern ssize_t logger_write_ext(const char*buf, unsigned long count);

+

 asmlinkage int printk(const char *fmt, ...)

 {

       va_list args;

       int r;

-

+      char trace_buf[1024];

+      int len = 0;

+

 #ifdef CONFIG_KGDB_KDB

       if (unlikely(kdb_trap_printk)) {

                va_start(args, fmt);

@@ -800,7 +804,9 @@

       va_start(args, fmt);

       r = vprintk(fmt, args);

       va_end(args);

-

+

+      len = vsnprintf(trace_buf, 1024, fmt, args);

+      logger_write_ext(trace_buf,len+1);

       return r;

 }

原创粉丝点击