在Android核心库中添加Log

作者:Aningsk ,本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。

一、Java核心库中添加Log

我主要参考了这三个博客:

http://blog.****.net/a345017062/article/details/6436264

http://blog.****.net/yuan1590/article/details/7920882

http://nsec.sjtu.edu.cn/~syma/blog/android_log_in_corelib.html

其中第三篇博客所描述的方法已经基本完善,在这里我只是就个人经验再次整理一下。

 

在Android中已经有了一套打印Log的系统(android.util.Log),但是这是建立在Android核心库之上的,所以在核心库中打印Log,是不能使用类似Log.i之类的方法了。在核心库中打印出Log方法的思想就是在核心库中再次封装一个Log方法,使其能够达到android.util.Log的效果。说白了就是复制粘贴。

作为在核心层替代android.util.Log的,我选择了java.io.File。应该也是可以使用其他的Java类,我没有试过。

 

1.首先,修改了File.java文件,将"安卓源码目录/frameworks/base/core/java/android/util/Log.java"中本地方法接口复制到"安卓源码目录/libcore/luni/src/main/java/java/io/File.java"中。File.java中如下图所示:

在Android核心库中添加Log

其中DEBUG=3是Log的级别,可以使用其他级别(在Log.java可以看到),但不能太低,级别太低的Log是不显示的。

有必要注意这几个定义与变量的修饰符(不要一股脑地复制粘贴)。除了Log方法是用public修饰外,其他的都是使用private修饰,作为File类的私有属性,对其他类不透明,不会被随意访问。而Log方法使用了public修饰,是为了这个Log方法能在核心库的任意地方被调用;但前面加了"@hide",这是因为Log方法作为Log类的公共方法已经在Log.java中定义。没有hide,android的编译器会发现两个同名的public方法,编译会失败。所以这里这个Log方法要隐藏起来。

 

2.修改File.java所对应的JNI文件。在上面我们在Java文件中添加了一个"native"的方法"println_native",并在Log方法中调用此方法。这个native方法需要在File.java对应的JNI文件中实现。具体文件是"安卓源码目录/libcore/luni/src/main/native/java_io_File.cpp"。

添加头文件:

在Android核心库中添加Log

然后我们添加println_native函数的实现,这其实是从"安卓源码目录/frameworks/base/core/jni/android_util_Log.cpp"复制过来的。java_io_File.cpp如下图:

在Android核心库中添加Log

注意函数的名字(这是JNI的规则),然后注意,在第187行加了一句"clazz = clazz",我不知道这个变量是干什么的,android_util_Log.cpp中是没有这句话的。但把这个函数复制到这里,编译会报错:说clazz这个变量没有被使用。所以我就在这个函数中使用一下这个变量,于是就有了"clazz = clazz"。

修改static JNINativeMethod gMethods[]数组,添加File_println_native函数的信息,如下图207行所示:

在Android核心库中添加Log

要注意一下函数File_println_native要在gMethods[]数组之前。这里已经是C++的世界了,不像Java里部分方法之间没有顺序。

 

3.具体使用。我当时是想要打Log看看android中读写文件的调用流程的,我在FileInputStream.java、FileOutputStream.java、IoBridge.java、Posix.java中加过Log。最后都能打印出来。首先,要加Log的文件中导入File类"import java.io.File;",然后就可以用了Log了:

在Android核心库中添加Log

如上图183行就是我加的Log。在eclipse中会打印出来,TAG是"FileInputStream_Log",内容是"read(……)"。

  

二、JNI中添加Log

这个问题在http://www.cnblogs.com/wanqieddy/archive/2012/10/22/2733855.html 中有相关说明。

思想也是重新封装LOGD之类的函数,介绍的挺清楚的:就是包含android/log.h头文件,#define LOGD(…) __android_log_print(XXX我不写了);对应的Android.mk添加LOCAL_LDLIBS = -llog。

 

呃……我还是写上吧:(2014-11-06)

必要的话,在对应的mk文件中加入:LOCAL_LDLIBS := -llog

#include <android/log.h>

#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "ProjectName", __VA_ARGS__) 

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

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , "ProjectName", __VA_ARGS__)

#define LOGW(...) __android_log_print(ANDROID_LOG_WARN  , "ProjectName", __VA_ARGS__)

#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , "ProjectName", __VA_ARGS__)

ProjectName就是TAG

使用时,例如:

LOGD("This is my log.");

这样就会打印出类似于如下的log:

D/ProjectName( 1625): This is my log.

 

但我在实际操作的时候,一开始按这个博客中的方法改,发现编译的时候说我重新封装的LOGD已经被定义。(嗯……11-06就遇到要自己加这些东西的情况了。)那我就尝试着直接使用LOGD函数,其他要加的东西我没有加,但是编译通过了。Log也打印出来了。可能是有同事,已经解决了在JNI中使用LOGD的问题了吧~?不清楚,总之Log是出来了,TAG是这个JNI文件所对应的Java类名。

 

到现在,Android底层的也可以打印Log了。

 

 

Aningsk

2014-7-10