A: 传统 logcat 在高频日志场景下有以下问题:
- 每条日志需要多次系统调用
- 多消费者时重复读取和解析
- 延迟高(10-50ms)
- CPU 占用高
logcat_daemon 通过共享内存实现零拷贝传输,解决这些问题。
A:
- Android 10+ (API 29): 基本功能支持
- Android 15: 需要 SELinux 策略配置
A: 不需要 Root,但需要:
- 系统权限(
log和system组) - SELinux 策略允许
如果是普通 App,只能作为消费者使用。
A:
- 写入延迟: < 1 μs
- 端到端延迟: < 5 ms
- 吞吐量: > 100,000 条/秒
- CPU 占用: < 1%
A: 确保在 AOSP 环境编译,或安装相应的 NDK 库。
# AOSP 编译
source build/envsetup.sh
lunch <target>
mma logcat_daemonA: 检查以下几点:
# 1. 检查权限
adb shell ls -la /system/bin/logcat_daemon
# 2. 检查 SELinux
adb shell getenforce
# 3. 查看日志
adb shell logcat -s logcat_daemon:V
# 4. 临时禁用 SELinux 测试
adb shell setenforce 0A: 查看 SELinux 拒绝日志:
adb shell dmesg | grep avc | grep logcat_daemon根据报错添加相应规则到 .te 文件。
A: 链接 liblog_consumer.so 并调用 API:
#include <log_consumer.h>
int main() {
logdaemon::LogConsumer consumer;
if (consumer.connect("/dev/socket/system_logs_v1")) {
logdaemon::LogEntry entry;
while (consumer.read(entry)) {
// 处理日志
}
}
return 0;
}A: 检查:
# 1. Daemon 是否运行
adb shell ps -A | grep logcat_daemon
# 2. Socket 是否存在
adb shell ls -la /dev/socket/system_logs_v1
# 3. Socket 路径是否正确
# 默认: /dev/socket/system_logs_v1A: 可能原因和解决:
-
缓冲区太小
# 增大缓冲区 logcat_daemon --size 8192 -
消费者处理太慢
- 使用批量读取
- 异步处理
- 减少格式化开销
-
系统负载高
- 检查 CPU 占用
- 优化消费者逻辑
A: 在消费者端过滤:
consumer.set_callback([](const logdaemon::LogEntry& entry) {
// 按优先级过滤
if (entry.priority < static_cast<uint8_t>(logdaemon::LogPriority::WARN)) {
return;
}
// 按包名过滤
if (strstr(entry.tag, "MyApp") == nullptr) {
return;
}
// 处理
std::cout << entry.message << std::endl;
});A: 每个消费者独立连接,各自维护读位置:
// 消费者 1
LogConsumer consumer1;
consumer1.connect("/dev/socket/system_logs_v1");
// 消费者 2
LogConsumer consumer2;
consumer2.connect("/dev/socket/system_logs_v1");
// 两者独立读取,互不影响A:
-
禁用实时优先级
logcat_daemon --no-realtime
-
检查消费者是否卡住
-
降低读取频率
while (consumer.read(entry)) { usleep(10000); // 10ms 间隔 }
A: 减小缓冲区大小:
logcat_daemon --size 1024 # ~1.1 MBA: 检查:
-
logd 缓冲区
logcat -G 1M # 减小 logd 缓冲区 -
消费者处理速度
- 使用批量读取
- 异步处理
-
系统负载
- 检查其他进程 CPU 占用
A: Binder 适合 RPC,但对于高频日志传输:
- 每次传输需要序列化/反序列化
- 有系统调用开销
- 大数据量时效率低
共享内存更适合高频大数据传输。
A: 使用无锁设计:
- 写指针使用原子递增
- 读指针独立维护
- 不需要锁,仅内存屏障
A:
- 原子操作保证指针更新
- 内存屏障保证写入顺序
- 单生产者设计避免写入竞争
A:
- Daemon 崩溃: 消费者 mmap 失效,需要重连
- Consumer 崩溃: Daemon 无感知,新消费者从头开始
A: 当前设计是单生产者(daemon),多消费者。多生产者需要更复杂的无锁算法(如 MPMC 队列),会增加开销。
A: 在消费者端实现:
#include <fstream>
std::ofstream log_file("/data/logs/system.log");
consumer.set_callback([&log_file](const LogEntry& entry) {
log_file << LogParser::format(entry) << std::endl;
});A: 消费者端实现网络发送:
consumer.set_callback([](const LogEntry& entry) {
// 通过 HTTP/gRPC 发送到服务器
send_to_server(entry);
});A: 使用示例消费者:
adb shell /system/bin/log_consumer_example或自己实现 UI 展示。
A: 完全兼容。Daemon 只是读取 logd,不影响 logcat 命令使用。
A: 不会。Daemon 只读取 logd,不修改任何系统行为。
A: Apache License 2.0,可自由使用和修改。
A:
- Fork 项目
- 创建功能分支
- 提交 Pull Request
请确保:
- 代码风格一致
- 添加单元测试
- 更新相关文档
A:
- GitHub Issues: 功能请求和 Bug 报告
- 讨论区: 使用问题和技术讨论