2.2 JNI框架层实例分析

框架层大量使用了JNI技术来完成对系统运行库的调用。深入理解JNI对分析框架层代码十分有用。本节将以框架层的实例详细讲解JNI编程的三个步骤。

在Android应用程序开发中,一般是调用应用框架层的android.util.Log.java提供的Java接口来使用日志系统。比如我们会写如下代码输出日志:


Log.d(TAG,"debug log");


这个Java接口其实是通过JNI调用系统运行库(即本地库)并最终调用内核驱动程序Logger把Log写到内核空间中的。在Android中,Log系统十分通用,而且其JNI结构非常简洁,很适合作为JNI入门的例子。本节就以它为例贯穿始终,详细讲解JNI各部分的内容。

本节所涉及的文件包括:

frameworks/base/core/jni/android_util_Log. cpp(JNI层实现代码)

frameworks/base/core/java/android/util/Log. java(Java层代码)

libnativehelper/include/nativehelper/jni. h(JNI规范的头文件)

libnativehelper/include/nativehelper/JNIHelp. h

libnativehelper/JNIHelp. cpp

frameworks/base/core/jni/AndroidRuntime. cpp

读者可以在Source Insight或者Eclipse中打开这几个文件为下面的分析做准备。

2.2.1 Log系统Java层分析

首先看Log系统Java层部分。打开Log.java文件,可以看到这里面只定义了isLoggable和println_native两个Native方法,其代码如下:


package android.util;

public final class Log{

……

public static int d(String tag, String msg){

//使用Native方法打印日志。LOG_ID_MAIN表示日志ID,有4种:main、radio、events、system

return println_native(LOG_ID_MAIN, DEBUG, tag, msg);

}

……

//声明Native方法isLoggable

public static native boolean isLoggable(String tag, int level);

……

/*@hide/public static final int LOG_ID_MAIN=0;

/*@hide/public static final int LOG_ID_RADIO=1;

/*@hide/public static final int LOG_ID_EVENTS=2;

/*@hide/public static final int LOG_ID_SYSTEM=3;

//声明Native方法println_native

/*@hide/public static native int println_native(int bufID,

int priority, String tag, String msg);

}


Java层需要做的就这么简单。只需要声明方法为native而无需实现,就可以直接调用,不会出现任何编译错误。

接下来看JNI层的实现代码。