LA和RTOS日志系统

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zoosenpin/article/details/78376363

1 Linux Android日志系统
1.1 内核logger机制
@ drivers/staging/android/logger.c
static size_t logger_offset(struct logger_log *log, size_t n)
{
    return n & (log->size - 1);
}
Write的off存在logger_log中(即内核内存buffer),而r_off存在于读的进程中。所以执行两次不同的logcat,都是从头开始读的。

1.2 logd日志进程
1.2.1 Legacy
#ifndef LOG_PRI
#define LOG_PRI(priority, tag, ...)                                   \
    ({                                                                 \
       if (((priority == ANDROID_LOG_VERBOSE) && (LOG_NDEBUG == 0)) ||  \
           ((priority == ANDROID_LOG_DEBUG) && (LOG_NDDEBUG == 0))  ||  \
           ((priority == ANDROID_LOG_INFO) && (LOG_NIDEBUG == 0))   ||  \
            (priority == ANDROID_LOG_WARN)                          ||  \
            (priority == ANDROID_LOG_ERROR)                         ||  \
            (priority == ANDROID_LOG_FATAL))                            \
                (void)android_printLog(priority, tag, __VA_ARGS__);     \
    })
#endif
对于WARN、ERROR、FATAL级别的log可以直接输出,而对于VERBOSE、DEBUG、INFO级别的log必需在定义相应宏的情况下才可以输出,所以需要在相应的文件中定义MACRO。

1.2.2 New ARCH
设置log等级环境变量:ANDROID_LOG_TAGS
全部打开
export ANDROID_LOG_TAGS="*:v"
全局过滤
export ANDROID_LOG_TAGS="ActivityManager:I MyApp:D * :S"

1.2.3 logwrapper
logwrapper /system/bin/mytest
或者
service logwrapper /system/bin/logwrapper /system/bin/mytest
    user root
    group root
    oneshot

logwrapper - 将被执行进程的stdio重定向到logd进程,然后通过logcat查看log。

1.2.4 调整logcat打印时间
diff --git a/liblog/logprint.c b/liblog/logprint.c
index c2f1545..75d095d 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -907,7 +907,10 @@ char *android_log_formatLogLine (
      * brackets, asterisks, or other special chars here.
      */
 #if !defined(_WIN32)
-    ptm = localtime_r(&(entry->tv_sec), &tmBuf);
+    //ptm = localtime_r(&(entry->tv_sec), &tmBuf);
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    ptm = localtime(&(tv.tv_sec));
 #else
     ptm = localtime(&(entry->tv_sec));
 #endif

1.2.5 Logd不能打印dmesg
diff --git a/logd/main.cpp b/logd/main.cpp
index a3241d0..457be8e 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -277,6 +277,7 @@ static bool property_get_bool_svelte(const char *key) {
         property_get("ro.build.type", property, "");
         not_user = !!strcmp(property, "user");
     }
+    not_user = true;
     return property_get_bool(key, not_user
             && !property_get_bool("ro.config.low_ram", false));
 }

1.2.6 URLs
log android调试神器
https://blog.csdn.net/by317966834/article/details/11892581

Android L日志系统1——logd
https://blog.csdn.net/koffuxu/article/details/53893297

1.3 Linux early_printk和early_console

1.4 Linux printk
四个重要变量:
static u64 log_first_seq; //指向当前可读的struct log 索引号
static u32 log_first_idx; //指向环形缓冲区可以读的位置

staticu64 log_next_seq; //指向当前可写的struct log 索引号
static u32 log_next_idx; //指向环形缓冲区可写的位置

@ init.xx.rc
service xxx /system/bin/xxx
    class main
    console // 将stdio定向到/dev/console,否则到/dev/null

1.5 Linux Pstore - Persistent Storage
主要用于存储内核异常时的log信息。实现方式是,管理一块“非易失性的存储空间”,如不断电的RAM或外部存储,当系统异常时,将log信息写到Pstore管理的存储空间,直到下一次系统正常时,再将log读出来,以文件形式提供给用户使用。

ramoops&pstore简要说明
https://blog.csdn.net/zangdongming/article/details/37729315

2 FreeRTOS简单log系统的实现
@ oem_log.c
#define USE_WAIT_QUEUE
#define TASK_BUF_SZ 2048

#define LINE_BUF_SZ 1024
#define LOG_BUF_SZ 4096
#define LOG_BUF_MASK  (LOG_BUF_SZ - 1)
#define LOG_BUF(idx)  (log_buf[(idx) & LOG_BUF_MASK])

static unsigned char line_buf[LINE_BUF_SZ];
static unsigned char log_buf[LOG_BUF_SZ];
static unsigned int log_start = 0, con_start = 0;
static unsigned int log_end = 0;

static unsigned int cdc = 0; /* char dropped count */
static SemaphoreHandle_t log_sem = NULL;

#if 1
#define log_lock() do {                    \
    if (NULL != log_sem) {                       \
        xSemaphoreTake(log_sem, portMAX_DELAY);  \
    }                                               \
} while (0)
#define log_unlock() do {                    \
    if (NULL != log_sem) {                       \
        xSemaphoreGive(log_sem);                 \
    }                                               \
} while (0)
#else
#define log_lock() do {} while(0)
#define log_unlock() do {} while(0)
#endif

#if 1
static int do_write_log2emmc(const char *buf, const uint16_t nbytes)
{
    FIL fil;
    FRESULT fr;
    const char *bufp = buf;
    uint16_t nleft, nwritten = 0;
    uint8_t cnt = 0;
    
    if (NULL == buf) {
        return 0;
    }
    nleft = nbytes;
    
    fr = f_open(&fil, LOG_FNAME, FA_OPEN_APPEND | FA_WRITE);
    if (FR_OK == fr) {
        while ((nleft > 0) && (cnt++ < 5)) {
            fr = f_write(&fil, bufp, nleft, &nwritten);
            if ((FR_OK == fr) && (nwritten > 0)) {
                bufp += nwritten;
                nleft -= nwritten;
            }
        }
        cdc += nleft;
        f_close(&fil);
    }

    if (nbytes == nleft) {
        return -1;
    }
    return (nbytes - nleft);
}
#endif

static inline void emit_char(const uint8_t c)
{
    LOG_BUF(log_end) = c;
    log_end++;

    if ((log_end - log_start) > LOG_BUF_SZ) {
        log_start = log_end - LOG_BUF_SZ;
        cdc++;
    }

    if ((log_end - con_start) > LOG_BUF_SZ) {
        con_start = log_end - LOG_BUF_SZ;
    }
}

int oem_sh_log(const char *buf, const char *fmt,...)
{
    hal_rtc_time_t local_time = {0};
    int16_t i, n, ts_len = 0;
#if defined (USE_WAIT_QUEUE)
    uint8_t msg_id;
#endif
    static uint32_t nr_data = 0;
    va_list ap;

    log_lock();

    if (buf && (buf[0] != 0x55)) {
#if 1
        n = do_write_log2emmc(buf, strlen(buf));
#endif
    } else {
        if (buf && (buf[0] == 0x55)) {
        } else {
            hal_rtc_get_time(&local_time);
            ts_len = snprintf(line_buf, LINE_BUF_SZ, "[%d/%d/%d %02d:%02d:%02d]<%d> ",
                    local_time.rtc_year + 2000,
                    local_time.rtc_mon,
                    local_time.rtc_day,
                    local_time.rtc_hour,
                    local_time.rtc_min,
                    local_time.rtc_sec,
                    nr_data++);
        }
        va_start(ap, fmt);
        if (ts_len > 0) {
            n = vsnprintf(line_buf + ts_len, LINE_BUF_SZ - ts_len, fmt, ap);
        } else {
            n = vsnprintf(line_buf, LINE_BUF_SZ, fmt, ap);
        }
        va_end(ap);

        if (n > 0) {
            if (ts_len > 0) {
                n += ts_len;
            }

            for (i = 0; i < n; i++) {
                emit_char(line_buf[i]);
            }
        }
    }

#if defined (USE_WAIT_QUEUE)
    if ((log_end - log_start) >= (LOG_BUF_SZ - 1024)) {
        msg_id = 1;
        xQueueSend(task_wait_queue, &msg_id, 0);
    }
#endif

    log_unlock();

    return n;
}

static void sh_log_task(void *data)
{
    bool to_send;
    unsigned char tbuf[TASK_BUF_SZ];
    uint16_t i;
#if defined (USE_WAIT_QUEUE)
    uint8_t msg_id;
#endif

    while (1) {
        log_lock();
#if 0
        if (1 == (log_end - log_start)) {
            log_start = 0;
            log_end = 0;
        } else
#endif
        if (log_start < log_end) {
            for (i = 0; (i < (TASK_BUF_SZ - 1)) && (log_start < log_end);
                    i++, log_start++) {
                tbuf[i] = LOG_BUF(log_start);
            }

            tbuf[i] = '\0';
            to_send = true;
        }

        log_unlock();

        if (to_send) {
            to_send = false;

            // oem_log("%s", tbuf);
#if 1
            do_write_log2emmc(tbuf, strlen(tbuf));
#endif
            tbuf[0] = '\0';
        }

#if defined (USE_WAIT_QUEUE)
        // block here, don't care return value
        xQueueReceive(p_slc_dev->task_wait_queue, &msg_id, (10000 / portTICK_PERIOD_MS));
#else
        vTaskDelay(100 / portTICK_PERIOD_MS);
#endif
    }

    vTaskDelete(NULL);
}

猜你喜欢

转载自blog.csdn.net/zoosenpin/article/details/78376363
LA