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
相关文章:

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)&am…...

【openresty服务器】:源码编译openresty支持ssl,增加service系统服务,开机启动,自己本地签名证书,配置https访问
1,openresty 源码安装,带ssl模块 https://openresty.org/cn/download.html (1)PCRE库 PCRE库支持正则表达式。如果我们在配置文件nginx.conf中使用了正则表达式,那么在编译Nginx时就必须把PCRE库编译进Nginx…...

如何将网站提交百度收录完整SEO教程
百度收录是中文网站获取流量的重要渠道。本文以我的网站,www.mnxz.fun(当然现在没啥流量) 为例,详细讲解从提交收录到自动化维护的全流程。 一、百度收录提交方法 1. 验证网站所有权 1、登录百度搜索资源平台 2、选择「用户中心…...

【STM32】ADC|多通道ADC采集
本次实现的是ADC实现数字信号与模拟信号的转化,数字信号时不连续的,模拟信号是连续的。 1.ADC转化的原理 模拟-数字转换技术使用的是逐次逼近法,使用二分比较的方法来确定电压值 当单片机对应的参考电压为3.3v时,0~ 3.3v(模拟信…...

蓝桥杯算法日记|贪心、双指针
3412 545 2928 2128 贪心学习总结: 1、一般经常用到sort(a,an);【a[n]】排序,可以给整数排,也可以给字符串按照字典序排序 2、每次选最优 双指针 有序数组、字符串、二分查找、数字之和、反转字…...

ArcGIS Pro SDK (二十七)自定义许可
ArcGIS Pro SDK (二十七)自定义许可 环境:Visual Studio 2022 + .NET6 + ArcGIS Pro SDK 3.0 文章目录 ArcGIS Pro SDK (二十七)自定义许可1 在Config.xaml中添加扩展配置2 在Module1.cs中实现接口IExtensionConfig1 在Config.xaml中添加扩展配置 <modules><inse…...

通过客户端Chatbox或OpenwebUI访问识别不到本地ollama中的模型等问题的解决
Chatbox和Open WebUI 等无法获取到 Ollama里的模型,主要是由以下原因导致: Ollama 服务未正确暴露给 Docker 容器或客户端模型未正确下载或名称不匹配网络配置或权限问题 排查以上问题的思路首先排查ollama服务是否启动,然后再看端口号 使…...

速度超越DeepSeek!Le Chat 1100tok/s闪电回答,ChatGPT 4o和DeepSeek R1被秒杀?
2023年,当全球科技界还在ChatGPT引发的AI狂潮中沉浮时,一场来自欧洲的"静默革命"正悄然改变游戏规则。法国人工智能公司Mistral AI推出的聊天机器人Le Chat以"比ChatGPT快10倍"的惊人宣言震动业界,其背后承载的不仅是技术…...

JVM速成=。=
JVM跨平台原理 跨平台:一次编译,到处运行 本质:不同操作系统上运行的JVM不一样,只需要把java程序编译成一份字节码文件,JVM执行不同的字节码文件。 Java是高级语言,提前编译一下(变成字节码文件…...

Packer 手动修复安装腾讯云插件
文章目录 Packer [腾讯云插件文档](https://developer.hashicorp.com/packer/integrations/hashicorp/tencentcloud) 提供的版本:v1.2.0,目前 Packer 构建镜像时,不支持现有2种[硬盘类型](https://www.tencentcloud.com/zh/document/product/…...

学习总结三十
下头论文 # P10605 下头论文 题目背景 莲子一直在苦恼关于论文的灵感。她为此花了太多时间,以至于没有时间理会她的伙伴梅莉。 题目描述 一天,莲子发现了一个绝妙的点子,并希望通过实验等过程将其完善。具体来说,她需要依次完成 n…...

开发完的小程序如何分包
好几次了,终于想起来写个笔记记一下 我最开始并不会给小程序分包,然后我就各种搜,发现讲的基本上都是开发之前的小程序分包,可是我都开发完要发布了,提示我说主包太大需要分包,所以我就不会了。。。 好了…...

Flutter PIP 插件 ---- Android
在 Flutter Android 应用中实现画中画功能 画中画(Picture-in-Picture, PiP)模式允许您的应用在一个固定在屏幕角落的小窗口中运行,同时用户可以与其他应用进行交互。本指南将介绍如何在 Flutter Android 应用中实现画中画功能,包括其局限性和解决方案。 项目地址 flutter_p…...

【20250211】字符串:459.重复的子字符串
#方法一:暴力求解法 # class Solution: # def repeatedSubstringPattern(self, s): # n len(s) # substr "" # #只重复一次不算“重复多次” # if n < 1: # return False # else: # …...

【DeepSeek学Cuda】矩阵转置:行读取优先还是列读取优先。
目录 **1. 实现A(按行读取,按列存储)2. 实现B(按列读取,按行存储)**3. 哪种更好 Professional cuda programming5. "当L1缓存被禁用时,所有内存访问都直接指向全局内存(Global …...

如何将3DMAX中的3D文件转换为AutoCAD中的2D图形?
大家好,今天我们来探讨一下如何将3DMAX中的3D文件转换为AutoCAD中的2D图形。无论是出于设计交流、施工准备还是其他实际需求,这种转换在工程设计领域都是一项非常实用的技能。接下来,我将为大家详细介绍几种实现这一转换的方法,帮助大家轻松跨越3D与2D设计之间的鸿沟。让我…...

Softhsm储存安全数据性能整理
目标:存储百万条数据对象 测试方案一:总大小2GB,每个数据对象大小约512KB,总条数4096条; 测试方案一:总大小2GB,每个数据对象大小约256B,总条数8388608条; 测试环境&am…...

【C++】——精细化哈希表架构:理论与实践的综合分析
先找出你的能力在哪里,然后再决定你是谁。 —— 塔拉韦斯特弗 《你当像鸟飞往你的山》 目录 1. C 与哈希表:核心概念与引入 2. 哈希表的底层机制:原理与挑战 2.1 核心功能解析:效率与灵活性的平衡 2.2 哈希冲突的本质&#x…...

【cocos creator】拖拽排序列表
DEMO下载 GameCtrl.ts import ItemCtrl from "./ItemCtrl";const { ccclass, property } cc._decorator;ccclass export default class GameCtrl extends cc.Component {property(cc.Node)content: cc.Node null;property(cc.Node)prefab: cc.Node null;arr []…...

b站——《【强化学习】一小时完全入门》学习笔记及代码(1-3 多臂老虎机)
问题陈述 我们有两个多臂老虎机(Multi-Armed Bandit),分别称为左边的老虎机和右边的老虎机。每个老虎机的奖励服从不同的正态分布: 左边的老虎机:奖励服从均值为 500,标准差为 50 的正态分布,即…...

【Mac排错】ls: command not found 终端命令失效的解决办法
【TroubleShooting on Mac】ls: command not found 终端命令失效的解决办法 A Solution to Solve “Command not found” of Terminal on Mac 一直在使用心爱的MacBook Pro的Terminal,并且为她定制了不同的Profile。 这样,看起来她可以在不同季节&…...

探秘Hugging Face与DeepSeek:AI开源世界的闪耀双子星
目录 一、引言:AI 开源浪潮的澎湃二、Hugging Face:AI 开源社区的基石(一)起源与发展历程(二)核心技术与特色(三)在 AI 领域的广泛应用 三、DeepSeek:东方崛起的 AI 新势…...

SkyWalking 10.1.0 实战:从零构建全链路监控,解锁微服务性能优化新境界
文章目录 前言一、集成SkyWalking二、SkyWalking使用三、SkyWalking性能剖析四、SkyWalking 告警推送4.1 配置告警规则4.2 配置告警通知地址4.3 下发告警信息4.4 测试告警4.5 慢SQL查询 总结 前言 在传统监控系统中,我们通过进程监控和日志分析来发现系统问题&…...

本地部署DeepSeek-R1(Mac版)
本地部署DeepSeek-R1(Mac版) 前言:过年这段时间,DeepSeek火遍全球,但遭受黑客攻击,10次对话基本9次都是服务器繁忙,请稍后重试。那么,本地部署整起来 总体来说,本地部署…...

网易易盾接入DeepSeek,数字内容安全“智”理能力全面升级
今年农历新年期间,全球AI领域再度掀起了一波革命性浪潮,国产通用大模型DeepSeek凭借其强大的多场景理解与内容生成能力迅速“出圈”,彻底改写全球人工智能产业的格局。 作为国内领先的数字内容风控服务商,网易易盾一直致力于探索…...

apachePoi中XSSFClientAnchor图片坐标简述;填充多张图片
概述 业务中经常会遇到在单元格内填充图片的需求,而且要求指定图片在单元格内的位置。 一般都是用的apache的poi,设置图片坐标。 HSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, short col1, int row1, short col2, int row2)dx1 dy1 起始单元…...

Java、Go、Rust、Node.js 的内存占比及优缺点分析
在选择编程语言进行项目开发时,内存占用是一个重要的考量因素。不同语言在内存管理、垃圾回收、并发模型等方面各有特点,影响着它们的内存使用情况。本文将对 Java、Go、Rust 和 Node.js 的内存占比进行对比,并分析它们的优缺点。 1. Java 的…...

C++智能指针的使用
文章目录 智能指针的使用和原理智能指针的使用场景RAII和智能指针C标准库智能指针的使用 智能指针的使用和原理 智能指针的使用场景 1. 下面的程序中,new了以后,我们也delete了,但是因为抛异常导致后面的delete没有得到执行,所以…...

计算机毕业设计——Springboot的社区维修平台旅游管理
📘 博主小档案: 花花,一名来自世界500强的资深程序猿,毕业于国内知名985高校。 🔧 技术专长: 花花在深度学习任务中展现出卓越的能力,包括但不限于java、python等技术。近年来,花花更…...

MySQL ALTER 命令详解
MySQL ALTER 命令详解 引言 MySQL 是一款广泛使用的开源关系数据库管理系统,ALTER 命令在 MySQL 数据库管理中扮演着至关重要的角色。ALTER 命令用于修改现有的数据库、表或列的定义。本文将详细介绍 MySQL ALTER 命令的用法、功能及其在实际应用中的重要性。 ALTER 命令概…...