在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中如下图所示:
其中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"。
添加头文件:
然后我们添加println_native函数的实现,这其实是从"安卓源码目录/frameworks/base/core/jni/android_util_Log.cpp"复制过来的。java_io_File.cpp如下图:
注意函数的名字(这是JNI的规则),然后注意,在第187行加了一句"clazz = clazz",我不知道这个变量是干什么的,android_util_Log.cpp中是没有这句话的。但把这个函数复制到这里,编译会报错:说clazz这个变量没有被使用。所以我就在这个函数中使用一下这个变量,于是就有了"clazz = clazz"。
修改static JNINativeMethod gMethods[]数组,添加File_println_native函数的信息,如下图207行所示:
要注意一下函数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了:
如上图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