在Android有一些应用程序的日志输出是通过printf之类的标准函数输出的,这类log是无法记录到的。主要是由于init进程会把0,1,2三个fd指向到/dev/null,而其他进程都是由init fork出来的,所以标准输出和标准错误输出都会继承自父进程,所以默认也都是不打印出来的。

android init的实现在system/core/init/init.c中:


int main(int argc, char** argv) {......// At this point we're in the second stage of init.InitKernelLogging(argv);LOG(INFO) << "init second stage started!";......
}

init会执行log初始化动作,也就是把所有的标准输入标准输出和标准错误输出都指向/dev/null:


void InitKernelLogging(char* argv[]) {// Make stdin/stdout/stderr all point to /dev/null.int fd = open("/sys/fs/selinux/null", O_RDWR);if (fd == -1) {int saved_errno = errno;android::base::InitLogging(argv, &android::base::KernelLogger);errno = saved_errno;PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";}dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);if (fd > 2) close(fd);android::base::InitLogging(argv, &android::base::KernelLogger);}

android中提供了logwrapper程序用来重定向log的输出,重定向的log可以使用logcat查看,我们来看下他的实现机制又是怎样的呢?

logwrapper的源代码实现在system/core/logwrapper中,原理如下:

通过logwrapper的封装来执行一个command,logwrapper会fork一个子进程,并在子进程中exec执行cmd,父进程负责和子进程通讯,并记录子进程输出的log,父进程会根据logwrapper的参数来选择对应的log输出方式:


/* Log directly to the specified log */static void do_log_line(struct log_info *log_info, char *line) {if (log_info->log_target & LOG_KLOG) {klog_write(6, log_info->klog_fmt, line);}if (log_info->log_target & LOG_ALOG) {ALOG(LOG_INFO, log_info->btag, "%s", line);}if (log_info->log_target & LOG_FILE) {fprintf(log_info->fp, "%s\n", line);}}

父进程起到一个log重定向的作用,它收取子进程输出的log,并通过其他方式输出出来,从上面的一段实现上可以看出,父进程可以通过do_log_line来按照三种方式来输出:


(1)LOG_KLOG的方式输出,调用的是klog_write来输出kernel log(2)LOG_ALOG,这种是输出给logcat使用的log,默认是LOG INFO级别(3)LOG_FILE,输出log到指定file文件,在我看得这个版本代码中,此方法暂时还不可用

父进程和子进程采用的是ptty机制来做进程通讯的,具体实现在system/core/logwrapper/logwrap.c中:


int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,int log_target, bool abbreviated, char *file_path,void *unused_opts, int unused_opts_len) {pid_t pid;int parent_ptty;int child_ptty;struct sigaction intact;struct sigaction quitact;sigset_t blockset;sigset_t oldset;int rc = 0;LOG_ALWAYS_FATAL_IF(unused_opts != NULL);LOG_ALWAYS_FATAL_IF(unused_opts_len != 0);rc = pthread_mutex_lock(&fd_mutex);if (rc) {ERROR("failed to lock signal_fd mutex\n");goto err_lock;}/* Use ptty instead of socketpair so that STDOUT is not buffered */          //使用ptty代替socket,因为socket是有缓冲的parent_ptty = TEMP_FAILURE_RETRY(open("/dev/ptmx", O_RDWR));if (parent_ptty < 0) {ERROR("Cannot create parent ptty\n");rc = -1;goto err_open;}char child_devname[64];if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||ptsname_r(parent_ptty, child_devname, sizeof(child_devname)) != 0) {ERROR("Problem with /dev/ptmx\n");rc = -1;goto err_ptty;}child_ptty = TEMP_FAILURE_RETRY(open(child_devname, O_RDWR));if (child_ptty < 0) {ERROR("Cannot open child_ptty\n");rc = -1;goto err_child_ptty;}sigemptyset(&blockset);sigaddset(&blockset, SIGINT);sigaddset(&blockset, SIGQUIT);pthread_sigmask(SIG_BLOCK, &blockset, &oldset);pid = fork();if (pid < 0) {close(child_ptty);ERROR("Failed to fork\n");rc = -1;goto err_fork;} else if (pid == 0) {pthread_mutex_unlock(&fd_mutex);pthread_sigmask(SIG_SETMASK, &oldset, NULL);close(parent_ptty);                                       //创建的子进程会继承父进程的fd,所以要关闭不需要的fddup2(child_ptty, 1);dup2(child_ptty, 2);close(child_ptty);child(argc, argv);} else {close(child_ptty);                                            //父进程也要关闭不需要的fd,剩余的fd就是用于进程交互的fd了if (ignore_int_quit) {struct sigaction ignact;memset(&ignact, 0, sizeof(ignact));ignact.sa_handler = SIG_IGN;sigaction(SIGINT, &ignact, &intact);sigaction(SIGQUIT, &ignact, &quitact);}rc = parent(argv[0], parent_ptty, pid, status, log_target,abbreviated, file_path);}if (ignore_int_quit) {sigaction(SIGINT, &intact, NULL);sigaction(SIGQUIT, &quitact, NULL);}err_fork:pthread_sigmask(SIG_SETMASK, &oldset, NULL);err_child_ptty:err_ptty:close(parent_ptty);err_open:pthread_mutex_unlock(&fd_mutex);err_lock:return rc;}

示例:


servcie akmd /system/bin/logwrapper /sbin/akmd

android使用logwrapper进行log重定向相关推荐

  1. Android系统(118)---Android抓取各种log的方法

    Android抓取各种log的方法 转自 http://blog.csdn.net/matthewei6/article/details/50596983 1.logcat (四类log buffer ...

  2. Android 系统(38)---Android抓取各种log的方法

    Android抓取各种log的方法 http://blog.csdn.net/matthewei6/article/details/50596983 1.logcat (四类log buffer是ma ...

  3. Android NDK开发之 Android系统开发中LOG的使用

    浅谈Android系统开发中LOG的使用 转自:http://blog.csdn.net/luoshengyang/article/details/6581828

  4. imx6q android nfs normal boot log

    ---------------------------------------- imx6q android nfs  normal boot log 用nfs 启动, --------------- ...

  5. Android中日志打印 Log的使用

    文章目录 Log等级划分 Log使用规范 Android Studio中log使用 Logcat中选择筛选条件 Log信息颜色设置 Log信息说明 写一份便于使用的Log辅助类 Log等级划分 Log ...

  6. android jni 中实现 LOG 输出调试

    android jni 中实现 LOG 输出调试 在jni 文件夹下 android.mk文件中 添加 LOCAL_LDLIBS += -L$(SYSTEM)/usr/lib -llog 在jni中添 ...

  7. android log抓取方法,Android系统之Android抓取各种log的方法

    Android系统之Android抓取各种log的方法 2018年11月25日 | 萬仟网移动技术 | 我要评论 android之android抓取各种log的方法 1.logcat (四类log b ...

  8. 浅谈Android系统开发中LOG的使用【转】

    本文转载自:http://blog.csdn.net/luoshengyang/article/details/6581828 在程序开发过程中,LOG是广泛使用的用来记录程序执行过程的机制,它既可以 ...

  9. android 线程方式打印log到sd卡

    2019独角兽企业重金招聘Python工程师标准>>> package com.foundreams.profs_chinese.payutil; import java.text. ...

最新文章

  1. 微信开发--one.微信平台验证
  2. Asp.Net Core(.net内核)
  3. Hebb负向规则与矛盾解对
  4. vue 给iframe设置src_vue组件中使用iframe元素
  5. mysql sum id 5_mysql怎么使用sum()求id字段的和?
  6. java socket调用接口_java调用websocket接口
  7. 源码安装Bind 9.10 正式版 开启DLZ数据库支持 和 数据库view查询
  8. mysql高可用方案之主从架构(master-slave)
  9. No orientation specified, and the default is
  10. jquery-1.10.2_d88366fd.js和jquery-3.1.0.min.js 在用touch事件时候, event.changedTouches[0]报错的问题。...
  11. vuex模块相互调用
  12. xbox360自制系统服务器,没有想象那么难!XBOX360刷机详细教程
  13. 计算机考研复试【英语面试题汇总】
  14. Linux 内核 下载 编译 安装 2021 ubuntu
  15. 《嵌入式 – GD32开发实战指南》第7章 定时器
  16. python神经网络图像分类,图像分类卷积神经网络
  17. 网站安全防护措施有哪些
  18. 快捷方式查看系统的配置信息 使用dxdiag
  19. 生活中的定律——劣币驱逐良币
  20. 【编程题】【Scratch四级】2019.12 抽奖

热门文章

  1. 深度学习(GoogLeNet)
  2. 仿三星GalaxyS4阳光解锁
  3. 2020.4.23美团点评实习生笔试题目记录(5道编程题)
  4. java列表排序sort_java list(java list排序sort升序、降序)
  5. 行内元素与块级元素的区别
  6. 计算机硬盘虚拟内存是什么,内存磁盘(RAM作为虚拟硬盘)计算机加速Primo Ramdisk设置教程(详细)...
  7. 英特尔第六、七代酷睿不安全!存在USB调试缺陷
  8. python学习路线图分享
  9. 哪个选手不想赢?管泽元发博力挺京东
  10. linux中dd命令详解,Linux中DD命令详解