关于安卓调试的log系统

在安卓系统下,对应用程序的调试,有一个特有的方式,就是log系统,其实就和C语言中的printf函数的使用类似,但是,它是将调试信息存入了缓冲区内,而安卓有四个缓冲区,他的设计模式是模仿了linux内核中的缓冲区模式,将所有的调试信息放入缓冲区内循环打印。所以加上linux中的缓冲区,安卓是有5个缓冲区。安卓中打印缓冲区的指令是logcat,linux内核中使用printk函数,然后用dmesg可以查看。

安卓的四个缓冲区分别是main(主缓冲区)、system(后台服务)、radio(无线、上网、电话)、events(随机数据,比如通知栏)。

在应用中的使用方法:
Java中使用Log.d()
c/c++中使用LOGD()、LOGE()等等

在logcat中查看,默认打开的是main、system缓冲区。当然如果想要查看其它分区的缓冲区,可以使用-b参数来指定查看分区。

logcat -b main
logcat -b system
logcat -b radio
logcat -b events

logcat中查看的格式: 等级/标签tag(pid):调试内容

等级:(越往下等级越高)

V:verbose
D:debug
I:info
W:warning
E:error
F:fatal

标签:打印调试信息从哪个那个进程出来的。

pid:系统分配

现在我们对安卓的log系统已经有了大致的了解,接下来要说的就是如何在c/c++中使用,这个最好是要自己写过一遍,之前我也认为这个和printf、printk一样的使用,结果使用的时候出现了一些问题,因为它有一些需要注意的点,如果漏了就无法编译通过。接下来我就将我调试过程和其中的问题记录在下。

先简单记录一下在java中的使用方法,因为java都封装好了,所以使用起来比较方便,就直接调用就好了。下面给个例子,就能理解了。

String TAG = “hello”;
Log.d(TAG, “XXXXXXX”);
		-->	D/hello (pid):XXXXXX

接下来是在c\c++中的使用,首先先说明一下几个重要步骤:
1.添加头文件 #include <utils/Log.h>
2.使用LOGD
3.编译时链接动态库(libcutils)

第一点添加头文件就没什么说的了,第二点,在使用的时候,定义标签的时候比较特殊,标签必须定义在头文件前面,不然会报未定义,或者隐式声明的错误。接下来会有例子说明。(这个需要注意,但是后面LOGD我是自己定义了,所以没用这个方法,看完后面就知道了,主要是这个方法好像不太行,可能是书上的版本太低了,具体原因,我也没找到)
还有就是编译链接动态库,关于动态库,可以理解为就是.h中函数实现的.c文件,但是不被允许看到源码,所以被打包成动态库,所以我们想使用的时候,必须要链接动态库。就像我们在linux下应用编程使用了线程后,使用gcc编译时需要gcc main.c -o main -lpthread 是一样的。如果不链接动态库,一样是会报隐式声明的错误。接下来给个例子:

text.c

#include <stdio.h>
#define LOG_TAG "text"
#include <utils/Log.h>
#define LOG_TAG1 "keymatch"
#define LOGD(...) __android_log_print( ANDROID_LOG_DEBUG, LOG_TAG1, __VA_ARGS__)
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG1, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , LOG_TAG1, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , LOG_TAG1, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN  , LOG_TAG1, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , LOG_TAG1, __VA_ARGS__)
int main()
{
    
    
        LOGD("set logd text !!!");
        return 0;
}

Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := libcutils
LOCAL_LDLIBS := -llog
LOCAL_MODULE := atext
LOCAL_SRC_FILES := text.c
include $(BUILD_EXECUTABLE)

接下来我要说的就是我遇到的问题,我使用的平台是rk3566 安卓11版本,我不知道是版本问题还是什么,我在写Android.mk时加入了LOCAL_LDLIBS := -llog这个库,正常是可以不用加的,就是之前不知道为什么一直无法使用,就添加了,反正后面这个例子是可以使用的。
还用一个问题就是LOGD的使用,可以看到例子中添加了一句宏定义

#define LOGD(...) __android_log_print( ANDROID_LOG_DEBUG, "keymatch", __VA_ARGS__)

这个说明LOGD是在这里定义的,我一开始以为LOGD是在头文件中定义的,可以直接使用,结果编译一直不过,然后我加上这个宏之后就可以使用了,这里是需要注意的一点。其实就是使用了__android_log_print。而那个LOCAL_LDLIBS := -llog这个库好像就是定义了__android_log_print,所以需要被加入,具体的我还没有证实,但既然这样可以,那就先用着吧。
当然这个方法在编译动态库的时候可能会出问题,会提示cannot find -llog的错误。意思是找不到liblog.so这个库文件。因此需要改成 LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog 才可以正常编译。但是我这边编译动态库的时候,好像不用这样改也行,没发现编译时提示“cannot find -llog”的错误。

在最后插一个常用的过滤方法,有了前面的例子就更好理解了

logcat -s “keymatch”

加上等级

logcat -s “keymatch:D”

就是这里,他的TAG打印的是keymatch,而不是text所以我上面说那个方法不行,就是在这里。。。

总结:
我们为什么需要使用log系统?调试的时候直接用printf打印出来不是更加简单明了?但是ptintf会在前台打印,方便的就只有调试时候的你。所以安卓的这个机制就是将所有的应用程序的打印全部都放在了缓冲区内,如果可以的话,可以做到前台一点关于调试的打印信息都没有。

猜你喜欢

转载自blog.csdn.net/weixin_43069863/article/details/117461233