Android和DLT日志系统

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);
}
写的off存在logger_log中(即内核内存buffer),而r_off存在于读的进程中,所以执行两次不同的logcat,都是从头开始读的。

1.2 logd日志进程
1.2.1 Android 8.0 per-tag
setprop log.tag.<tagname> DEBUG
/data/local.prop

logcat <tagname>:D *:S &

1.2.2 logwrapper
logwrapper /system/bin/mytest
或者
service logwrapper /system/bin/logwrapper /system/bin/mytest
    user root
    group root
    seclabel u:r:init:s0
    oneshot

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

1.2.3 调整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.4 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.3 Linux printk
1.3.1 printk的原理
printk的实现原理很简单,在有了日志消息后,首先申请控制台的信号量,如果申请到,则调用控制台写方法,写控制台。

在内核源码树的kernel/printk.c中,使用宏DECLARE_MUTEX声明了一个互斥锁console_sem,他用于保护console驱动列表console_drivers及同步对整个console驱动系统的访问。其中定义了函数acquire_console_sem来获得互斥锁console_sem,定义了release_console_sem来释放互斥锁console_sem,定义了函数try_acquire_console_sem来尽力得到互斥锁console_sem。这三个函数实际上是分别对函数down,up和down_trylock的简单包装。需要访问console_drivers驱动列表时就需要使用acquire_console_sem来保护console_drivers列表,当访问完该列表后,就调用release_console_sem释放信号量console_sem。函数console_unblank,console_device,console_stop,console_start,register_console 和unregister_console都需要访问console_drivers,因此他们都使用函数对acquire_console_sem和release_console_sem来对console_drivers进行保护。

调试console_sem时,需要打开宏CONFIG_DEBUG_SPINLOCK以跟踪owner字段。

关闭kernel Log,通过bootchart.png可以看到启动init进程的时间明显提前,可以加快启动速度。
kernel/printk.c
int console_printk[4] = {
    DEFAULT_CONSOLE_LOGLEVEL,
    DEFAULT_MESSAGE_LOGLEVEL,
    MINIMUM_CONSOLE_LOGLEVEL,
    DEFAULT_CONSOLE_LOGLEVEL,
};
改为
int console_printk[4] = {
    0, //DEFAULT_CONSOLE_LOGLEVEL,
    0, //DEFAULT_MESSAGE_LOGLEVEL,
    0, //MINIMUM_CONSOLE_LOGLEVEL,
    0, //DEFAULT_CONSOLE_LOGLEVEL,
};
这四个值对应到路径proc/sys/kernel/printk,当printk()没有指定消息级别时,就采用DEFAULT_MESSAGE_LOGLEVEL(对应到KERN_WARNING = 4)。

echo "8 8 8 8" > /proc/sys/kernel/printk

Android中logcat读取dmesg后,不显示最前面的时间戳,所以不方便查找内核时间,可以使用如下的方式,在每次调用打印函数时,同时也打印下面的秒和微妙2个值,这样logcat读取的dmesg就不会丢失内核时间点 (28-Dec-2021)。
static void get_timestamp(
    u64 *sec, u64 *usec)
{
    u64 ts;
    u64 rem_ns;

    ts = local_clock();
    rem_ns = do_div(ts, 1000000000);
    /* %5lu */
    *sec = ts;
    /* %06lu */
    *usec = rem_ns / 1000;
}

1.3.2 修改Android Printk默认loglevel
修改这个值前,检查一下init中允许的最大值,否则改为8可能无效。

in init.rc
change
loglevel 3
to
loglevel 6

1.3.3 重定向服务stdio到/dev/console
init.xx.rc
service xxx /system/bin/xxx
    class main
    console # 将服务xxx的stdio定向到/dev/console,否则到/dev/null

1.3.4 pr_debug动态log
CONFIG_DEBUG_FS=y
CONFIG_DYNAMIC_DEBUG=y

echo "file my_drv.c +p" > \
/sys/kernel/debug/dynamic_debug/control

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

1.5 Linux logrotate
当第一次进行日志轮替时,当前的secure日志会自动改名为secure.1,然后新建secure日志,用来保存新的日志;当第二次进行日志轮替时,secure.1会自动改名为secure.2,当前的secure日志会自动改名为secure.1,然后也会新建secure日志,用来保存新的日志;以此类推。

2 GENIVI DLT
2.1 GENIVI systemd configuration file
/etc/systemd/system
/lib/systemd/system
/run/systemd/system
/usr/lib/systemd/user

2.2 commands
systemctl list-unit-files | grep enable

systemctl cat dlt-daemon.service
systemctl cat dlt-system.service

systemctl show dlt-daemon.service
systemctl show dlt-system.service

systemctl start dlt-recv-daemon.service

2.3 dlt viewer
/etc/dlt.conf
dlt viewer可以通过TCP、UDP和串口连接dlt daemon。

2.4 showcase
[21-Oct-2021]
dlt-receive -a localhost

2.5 DLT memory monitor
This is used to check OOM issue.
oom-killer: GFP_HIGHUSER_MOVABLE
Application ID: MON
Context ID: MSER
Context ID: THRD
The 1st para: timestamp
The 5th para: pgfault
The 8th para: active_anon

3 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;

/* char dropped count */
static unsigned int cdc = 0;
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);
}

4 Abbreviations
bail out:跳伞
dlt: Diagnostic Log and Trace
Slog.wtf:what a terrible failure
usr: Unix System Resource

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/69887.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安卓手游内存call综合工具/内部call/安卓注入call/数据分析(类人猿学院)

进程分析注入综合工具总界面 模块分析函数分析遍历 函数分析 so汇编分析 汇编call植入器&#xff0c;支持模拟器x86 x64 和手机arm64指令全平台 防ce搜索数据功能 全国首套发布&#xff0c;阿凡老师学院最好的安卓内存逆向老师&#xff0c;几乎行业最强的&#xff0c;有兴趣可以…

Kotlin 扩展

Kotlin 扩展 引言 Kotlin 作为一种现代编程语言,以其简洁、安全、互操作性强等特点,在 Android 开发领域占据了重要地位。其中,Kotlin 扩展(Extensions)是其一项非常实用的特性,它允许开发者以简洁的方式对类、对象或属性进行扩展。本文将详细介绍 Kotlin 扩展的概念、…

通过例子学 rust 个人精简版 1-1

1-1 Hello World fn main() {println!("Hello World!");// 动手试一试println!("Im a Rustacean!"); }Hello World! Im a Rustacean!要点1 &#xff1a;println 自带换行符 注释 fn main() {let x 5 /* 90 */ 5;println!("Is x 10 or 100? x …

ML.NET库学习007:从SQL数据库中流式读取数据并进行预测分析

文章目录 ML.NET库学习007:从SQL数据库中流式读取数据并进行预测分析项目主要目的和原理项目概述实现的主要功能主要流程步骤使用的主要函数方法关键技术主要功能和步骤功能详细解读实现步骤分步骤代码结构及语法解读使用机器学习进行特征工程:从类别到数值的转换与文本特征提…

闲鱼IP属地是通过电话号码吗?

在闲鱼这样的二手交易平台上&#xff0c;用户的IP属地信息对于维护交易安全、增强用户间的信任至关重要。然而&#xff0c;关于闲鱼IP属地是如何确定的&#xff0c;不少用户存在疑惑&#xff0c;尤其是它与电话号码之间是否存在关联。本文将深入探讨这一问题&#xff0c;揭示闲…

电商小程序(源码+文档+部署+讲解)

引言 随着移动互联网的快速发展&#xff0c;电商小程序成为连接消费者与商家的重要桥梁。电商小程序通过数字化手段&#xff0c;为消费者提供了一个便捷、高效的购物平台&#xff0c;从而提升购物体验和满意度。 系统概述 电商小程序采用前后端分离的架构设计&#xff0c;服…

【20250215】二叉树:94.二叉树的中序遍历

#方法一&#xff1a;递归法 # class Solution: # def inorderTraversal(self,root): # res[] # def dfs(node): # if node is None: # return # #下面代码是不对的&#xff0c;没有体现递归 # #res.a…

Windows环境安装Kafka(集群版)

大家好&#xff0c;最近在准备Java面试&#xff0c;复习到Kafka的相关知识&#xff0c;一时兴起&#xff0c;就想在自己的Windows笔记本上安装一个Kafka集群。下面就记录一下安装步骤。 工具分享 Offset Explorer&#xff1a;Kafka可视化工具 下载地址&#xff1a;https://ww…

完全数和质数算法详解

完全数是指一个正整数&#xff0c;它等于其所有真约数&#xff08;即除了自身以外的所有正因数&#xff09;之和。例如&#xff0c;6 是一个完全数&#xff0c;因为它的真约数是 1、2 和 3&#xff0c;且 1 2 3 6。 1 计算约数和 1.1 遍历 遍历其所有可能的约数并计算它们…

buu-jarvisoj_level2_x64-好久不见37

覆盖缓冲区和 RBP&#xff1a; 使用 128 8 字节覆盖 buf 和 rbp。 构造 ROP 链&#xff1a; pop rdi; ret 地址&#xff1a; 将 pop rdi; ret 指令的地址写入返回地址位置。 /bin/sh 地址&#xff1a; 将 /bin/sh 字符串的地址压入栈顶&#xff0c;作为 system 函数的参数。…

大模型训练为什么依赖GPU

近年来&#xff0c;随着人工智能技术的飞速发展&#xff0c;特别是深度学习领域的进步&#xff0c;大模型的训练逐渐成为研究和工业界的热点。作为大模型训练中的核心硬件&#xff0c;GPU&#xff08;图形处理单元&#xff09;扮演了至关重要的角色。那么&#xff0c;为什么大模…

Python的那些事第二十一篇:Python Web开发的“秘密武器”Flask

基于 Flask 框架的 Python Web 开发研究 摘要 在 Web 开发的江湖里,Python 是一位武林高手,而 Flask 则是它手中那把小巧却锋利的匕首。本文以 Flask 框架为核心,深入探讨了它在 Python Web 开发中的应用。通过幽默风趣的笔触,结合实例和表格,分析了 Flask 的特性、优势以…

Ubuntu+Laravel+MQ+Supervisor队列系统搭建流程

1、安装MQ环境 sudo apt install -y rabbitmq-server sudo systemctl enable rabbitmq-server --now 2、进入laravel项目&#xff0c;安装MQ队列驱动 composer require vladimir-yuldashev/laravel-queue-rabbitmq 3、配置 .env QUEUE_CONNECTIONrabbitmq RABBITMQ_HOST12…

5G与物联网的协同发展:打造智能城市的未来

引言 随着科技的不断进步&#xff0c;智能城市的概念已经不再是科幻小说中的幻想&#xff0c;它正在逐步走进我们的生活。而这背后的两大驱动力无疑是 5G和 物联网&#xff08;IoT&#xff09;。5G网络以其高速率、低延迟、大容量的优势&#xff0c;与物联网的强大连接能力相结…

python第七课

WSGI Middleware 中间件&#xff0c;可以理解称对应用程序的一组装饰器&#xff0c;对两边都起作用的元素。 重写environ&#xff0c;然后基于URL&#xff0c;将请求对象路由给不同的应用对象支持多个应用或者框架顺序地运行于同一个进程中通过转发请求和相应&#xff0c;支持负…

RAII(Resource Acquisition Is Initialization)机制

RAII&#xff08;Resource Acquisition Is Initialization&#xff09;机制 1. 什么是 RAII&#xff1f; &#x1f31f; RAII&#xff08;资源获取即初始化&#xff0c;Resource Acquisition Is Initialization&#xff09; 是 C 语言中的一种管理资源的编程技巧。 RAII 使资…

【kafka系列】日志存储设计 消息写入、读取

目录 日志存储设计 1. 日志存储的目录结构 2. 日志内容格式设计 3. 日志索引设计 4. 设计优势 消息写入流程 示例 流程图 消息读取流程 示例 关键设计细节 流程图 日志存储设计 Kafka的日志存储是其高吞吐、持久化能力的核心设计&#xff0c;其结构包含目录组织、…

vue3.x 自定义hook函数详细解读

1. 什么是自定义 Hook 函数&#xff1f; 自定义 Hook 函数是一个封装了逻辑的 JavaScript 函数&#xff0c;它可以使用 Vue 3 的 Composition API 提供的响应式数据和生命周期钩子。通过自定义 Hook&#xff0c;你可以将组件的逻辑拆分成更小、更可复用的单元。 特点&#xf…

是时候说再见了

说再见 2018 to 2025 2018&#xff1a;学习 2018年开始读研。师兄师姐们说可以写写CSDN博客&#xff0c;对找工作也有帮助。于是在12月4日&#xff0c;发布了自己的第一篇文章[翻译] 神经网络与深度学习 首页 - Index。当时还在学习各种基础知识&#xff0c;看到了这个英文文…

蓝桥杯篇---IAP15F2K61S2定时器

文章目录 前言简介定时器的工作模式1.模式02.模式13.模式24.模式3 定时器的寄存器1.TMOD2.TCON3.THO/TL04.TH1/TL1 定时器的使用步骤1.配置TMOD2.设置初值3.启动定时器4.使能中断5.编写中断服务函数 示例代码&#xff1a;定时器的基本使用代码说明示例代码&#xff1a;定时器1用…