Android中Log信息的输出方法

共两篇文章,第一篇讲述了如何在程序中输出Log信息,第二篇详细的分析了Log信息的输出机制。

 

下面是第一篇(转自:http://blog.163.com/binghaitao@126/blog/static/3383532520099309366435/)

 

1:在编译so文件的c或cpp文件之前中加入以下代码,就可以在android中的log显示日志内容
       #include <android/log.h>

       #define LOG_TAG "show infomation"

       #define LOGW(a )  __android_log_write(ANDROID_LOG_WARN,LOG_TAG,a)

 

2:就可以在c或cpp中加入LOWG(str) 就可以在android中的log中显示打印的内容

 

3.这样写完以后,如果直接编译,就会报 __android_log_write 方法undefined.

怎么回事呢?关键是在设置编译选项上面。

在Android.mk文件里,可以指定一个LOCAL_LDLIBS的参数。如果不指定,那么编译的时候,只会引入默认的几个重要的lib,比如libc之类的。

如果要用log,那就要把 liblog给引进来。

网上很多的写法是 LOCAL_LDLIBS := -llog ,这在build static lib的时候没什么问题。如果是build shared lib,就会报个 cannot find -llog的错误。意思是找不到liblog.so这个库文件。

因此需要改成 LOCAL_LDLIBS :=  -L$(SYSROOT)/usr/lib -llog 才可以正常编译。

其中-L参数是指定了搜索lib的路径。

下面是一个android.mk的内容的例子:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := TestNdkNetwork

LOCAL_SRC_FILES := HttpConnection.cpp

LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog

include $(BUILD_SHARED_LIBRARY)

 

 

下面是第二篇(转自http://blog.csdn.net/knock/archive/2010/04/21/5511255.aspx)


为了调试,必须要将log怎么打印的搞清楚,于是有了以下的分析。

我们通常在程序中插入LOGD(..),LOGE(..)之类的语句,但什么情况下可以查看这些打印消息呢?
首先,来到定义处:system/core/include/cutils/log.h,在开头就可以看到
#ifndef LOG_TAG
#define LOG_TAG NULL
#endif
所以程序中#include "log.h"之前要定义LOG_TAG,不然就为空.
再看LOGD的定义
#ifndef LOGD
#define LOGD(...) ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif
跟进
#ifndef LOG
#define LOG(priority, tag, ...) /
    LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
#endif
继续
#ifndef LOG_PRI
#define LOG_PRI(priority, tag, ...) /
    android_printLog(priority, tag, __VA_ARGS__)
#endif
再跟进
#define android_printLog(prio, tag, fmt...) /
    __android_log_print(prio, tag, fmt)

__android_log_print()是位于system/core/liblog/logd_write.c内
int __android_log_print(int prio, const char *tag, const char *fmt, ...)
{
    va_list ap;
    char buf[LOG_BUF_SIZE];   

    va_start(ap, fmt);
    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
    va_end(ap);

    return __android_log_write(prio, tag, buf);
}
看__android_log_write()
int __android_log_write(int prio, const char *tag, const char *msg)
{
    ......

    return write_to_log(log_id, vec, 3);
}
write_to_log定义如下
static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) =
    __write_to_log_init;
查看一下
static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
{
#ifdef HAVE_PTHREADS
    pthread_mutex_lock(&log_init_lock);
#endif

    if (write_to_log == __write_to_log_init) {
        log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
        log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
        log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);

        write_to_log = __write_to_log_kernel;

        if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||
                log_fds[LOG_ID_EVENTS] < 0) {
            log_close(log_fds[LOG_ID_MAIN]);
            log_close(log_fds[LOG_ID_RADIO]);
            log_close(log_fds[LOG_ID_EVENTS]);
            log_fds[LOG_ID_MAIN] = -1;
            log_fds[LOG_ID_RADIO] = -1;
            log_fds[LOG_ID_EVENTS] = -1;
            write_to_log = __write_to_log_null;
        }
    }

#ifdef HAVE_PTHREADS
    pthread_mutex_unlock(&log_init_lock);
#endif

    return write_to_log(log_id, vec, nr);
}
这段的主要意思是打开/dev/log/main,/dev/log/radio,/dev/log/events三个设备都成功则将

write_to_log指向__write_to_log_kernel,否则指向__write_to_log_null。
下面就分别看看这两个
static int __write_to_log_null(log_id_t log_fd, struct iovec *vec, size_t nr)
{
    return -1;
}

static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
{
    ssize_t ret;
    int log_fd;

    if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
        log_fd = log_fds[(int)log_id];
    } else {
        return EBADF;
    }

    do {
        ret = log_writev(log_fd, vec, nr);
    } while (ret < 0 && errno == EINTR);

    return ret;
}
__write_to_log_null()什么也不做,表示丢弃log信息。__write_to_log_kernel会调用log_writev()

将log写进对应的设备(/dev/log/*).

为什么写进init.rc里由init来执行的程序不能输出log呢?下面再来探究一番。。
system/core/init/init.c中,
void service_start(struct service *svc)函数启动服务,有这么一句
        if (needs_console) {
            setsid();
            open_console();
        } else {
            zap_stdio();
        }
而这两个函数为:
static void zap_stdio(void)
{
    int fd;
    fd = open("/dev/null", O_RDWR);
    dup2(fd, 0);
    dup2(fd, 1);
    dup2(fd, 2);
    close(fd);
}

static void open_console()
{
    int fd;
    if ((fd = open(console_name, O_RDWR)) < 0) {
        fd = open("/dev/null", O_RDWR);
    }
    dup2(fd, 0);
    dup2(fd, 1);
    dup2(fd, 2);
    close(fd);
}
zap_stdio()比较狠,直接将STDIN,STDOUT,STDERR都干掉了,而open_console()则只是在/dev/console

不存在的情况下才干掉STDIN,STDOUT,STDERR,如果/dev/console存在,则将所有输入输出重定向到它


调用哪个取决于needs_console,
needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
而svc->flags关于SVC_CONSOLE的部分来自于system/core/init/parser.c
static void parse_line_service(struct parse_state *state, int nargs, char **args)
{
       case K_console:
        svc->flags |= SVC_CONSOLE;
        break;

}
这也就是说如果init.rc中service部分有请求console,则可以打印到console。

但怎么样才能打印到系统的log中,可以使用logcat来查看呢?这就需要用到logwrapper。
system/core/logwrapper/logwrapper.c中,logwrapper先打开/dev/ptmx,查询到设备名后
fork()一个子进程并将STDOUT,STDERR定向到查询到的设备。
        // redirect stdout and stderr
        close(parent_ptty);
        dup2(child_ptty, 1);
        dup2(child_ptty, 2);
        close(child_ptty);
然后开始执行要运行的程序
 child(argc - 1, &argv[1]);


总结:
系统中的程序中输出log一般是到/dev/log/下的三个设备中,可以用logcat查看。
对于init运行的程序则有两种方法查看到log信息:
1.添加/system/bin/logwrapper,可以用logcat查看,例如
 service /system/bin/logwrapper /system/bin/rild
2.添加console,像sh一样直接输出到console
 service console /system/bin/sh
      console

 

                                                                              (完)

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

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

相关文章

寻求神谕的词语:谈海日寒诗集《空山集》

诗人杨炼曾用两个“他者”概括了当代中国诗歌所面对的两个检验体系&#xff1a;“背后是中文古典诗歌杰作”&#xff0c;“面前是古今世界文学精品”1。他提出&#xff1a;“全球化语境中&#xff0c;我们能否找到——创造一种更深也更新的标准来判断作品&#xff1f;去建立那个…

批量给Linux服务器推送文件、执行指令的工具推荐 - wgcloud-bach-agent

wgcloud-bach-agent是wgcloud官方开发的一个工具&#xff0c;具有批量给Linux主机上传文件&#xff0c;执行指令的功能 当我们有一个文件&#xff0c;需要上传到很多主机&#xff0c;或需要在很多主机执行同一条指令的时候&#xff0c;这个工具就非常实用了&#xff0c;可以极…

verilog中assign语句

/************************************** * Module: assign * Date:2014-08-10 * Author: hemmingway163.com * * Description: verilog中的assign语句的用法 ***************************************//* 一、引入语法的概念1、只有寄存器类型的信号才可以在always和initi…

Neutron Router 工作原理 - 每天5分钟玩转 OpenStack(142)

上一节我们创建了 router 连通了 vlan100 和 vlan101&#xff0c; 今天分析router是如何工作的。 首先查看控制节点的网络结构发生了什么变化&#xff1a; br-int 上多了两个 port: 1. qr-d295b258-45&#xff0c;从命名上可以推断该 interface 对应 router_100_101 的 interf…

android linux kernel VS standard linux kernel

在kernel子目录下存放的就是Android的Linux Kernel了, 通过和标准的Linux 2.6.25 Kernel的对比,我们可以发现,其主要增加了以下的内容: 1. 基于ARM架构增加Gold-Fish平台,相应增加的目录如下: kernel/arch/arm/mach-goldfish kernel/include/asm-arm/arch-go…

访问 Neutron 外部网络 - 每天5分钟玩转 OpenStack(143)

前面我们学习了位于不同 Neutron subnet 的 instance 可以通过 router 通信&#xff0c;今天开始讨论 instance 如何访问外部网络。 这里的外部网络是指的租户网络以外的网络。租户网络是由 Neutron 创建和维护的网络。 外部网络不由 Neutron 创建。如果是私有云&#xff0c;外…

使用函数实现数据大小端转换

使用函数实现数据大小端转换 题目描述 在数字芯片设计中&#xff0c;经常把实现特定功能的模块编写成函数&#xff0c;在需要的时候再在主模块中调用&#xff0c;以提高代码的复用性和提高设计的层次&#xff0c;分别后续的修改。 请用函数实现一个4bit数据大小端转换的功能。…

ISE报错问题集锦(转载)

1、XST - "ERROR:Xst:902 - .v, line xx: Unexpected event in always block sensitivity list." 解决方法&#xff1a;Resolution 1 XST does not currently support logical operators in the sensitivity list. Because these logical operators are not evaluate…

创建 OVS 外部网络 ext_net - 每天5分钟玩转 OpenStack(144)

上一节完成连接外网的配置准备工作&#xff0c;今天就来创建 OVS 外部网络 ext_net。 进入 Admin -> Networks 菜单&#xff0c;点击 “Create Network” 按钮。 显示创建页面。 Provider Network Type 选择 “Flat”。 Network 填写 “external”&#xff0c;与 ml2_conf.…

Linux学习之zImage内核镜像解压过程详解

zImage内核镜像解压过程详解 收藏 zImage内核镜像解压过程详解 作者&#xff1a; 刘洪涛&#xff0c;华清远见嵌入式培训中心 讲师。 本文以linux-2.6.14内核在S3C2410平台上运行为例&#xff0c;讲解内核的解压过程。 内核编译完成后会生成zImage内核镜像文件。关于…

4位数值比较器电路

4位数值比较器电路 题目描述&#xff1a;使用门级描述方式&#xff0c;实现4位数值比较器 某4位数值比较器的功能如下表 timescale 1ns/1nsmodule comparator_4(input [3:0] A ,input [3:0] B ,output wire Y2 , //A>Boutput wire Y1 …

将 ext_net 连接到 router - 每天5分钟玩转 OpenStack(145)

上一节完我们创建了外部网络 ext_net&#xff0c;接下来需要将其连接到 Neutron 的虚拟路由器&#xff0c;这样 instance 才能访问外网。 点击菜单 Project -> Network -> Routers 进入 router 列表。 点击 router_100_101 的 “Set Gateway” 按钮。 在 “External Netw…

Xilinx_ISE和ModelSim的联合使用方法 / 从Xilinx ISE 14.7启动ModelSim时遇到的问题

解决方法&#xff1a; 前提是安装了 xilinx ise14.7 和modelsim se 10.1a 1〉从Windows的Start Menu开始&#xff0c;Xilinx ISE Design Suite 14.7 —〉EDK —〉Tools —〉Compile Simulation Libraries 按照提示编译好library&#xff0c;编译的library输出目录是&#xff…

ML2 配置 OVS VxLAN - 每天5分钟玩转 OpenStack(146)

今天我们开始学习 OVS 如何实现 Neutron VxLAN&#xff0c;关于 VxLAN 的概念以及 Linux Bridge 实现&#xff0c;大家可以参考前面相关章节。 Open vSwitch 支持 VXLAN 和 GRE 这两种 overlay network。因为 OpenStack 对于 VXLAN 与 GRE 配置和实现差别不大&#xff0c;这里只…

4bit超前进位加法器电路

4bit超前进位加法器电路 题目描述 采用门级描述方式&#xff0c;实现此4bit超前进位加法器&#xff0c;接口电路如下&#xff1a; timescale 1ns/1nsmodule lca_4(input [3:0] A_in ,input [3:0] B_in ,input C_1 ,output wire CO …

Linux-Android系统启动之INIT进程和system v init

Linux系统启动之INIT进程和system v init 一. Linux系统启动之INIT进程和system v init 1. 首先介绍一下INIT进程   init进程在Start_kernel执行完毕之后&#xff0c;也就是Kernel初始化完毕之后启动&#xff0c;是系统所有进程的起点&#xff0c;内核在完成核内引导以后&a…

学习Zynq-7000的入门书单

根据选用的芯片型号和应用领域的不同&#xff0c;读者可以适当裁减。 Entrance Readings: 1. Zynq-7000 User Guides Zynq-7000 All Programmable SoC: Concepts, Tools, and Techniques http://www.xilinx.com/support/documentation/sw_manuals/xilinx14_4/ug873-zynq-ctt.pd…

创建 vxlan 并部署 instance - 每天5分钟玩转 OpenStack(147)

上一节我们完成了 OVS VxLAN 的配置工作&#xff0c;今天创建 vxlan100_net 并部署 instance。 创建 vxlan100_net 打开菜单 Admin -> Networks&#xff0c;点击 “Create Network” 按钮。 显示创建页面。 Provider Network Type 选择 “VXLAN”。 Segmentation ID 即 VNI…

有限编码器电路

有限编码器电路 题目描述 timescale 1ns/1nsmodule encoder_0(input [8:0] I_n ,output reg [3:0] Y_n ); // always (*)begin // casex(I_n) // 9b111111111 : Y_n 4b1111; // 9b0xxxxxxxx : Y_n 4b0110; // 9b10xxx…

Linux-Android启动之zImage生成过程详解

可以看到&#xff0c;在顶层makefile的第278行&#xff0c;包含了scripts/Kbuild.include文件&#xff0c;在这里定义了大量的函数和变量&#xff0c;供顶层makefile和其他makefile文件使用。 在顶层makefile文件的第412行&#xff0c;包含了arch/arm/Makefile。这个是体系结…