1. 添加Android JNI 接口到Android 代码树
1.1 假定需要被测试Jni 接口是TestNativeApi.java, 将其添加到Android的代码树下 frameworks/base/core/jni/TestNativeApi.java 这个Native程序,在Android中被编译成jar包形式,可以被上层Android java应用调用。 而其static 函数中调用 android System.loadLibrary() 来调用下层C++ 的 .so 库,并且loadLibrary()会判断 .so库的类型, 如果是C++ 的jni库,则会调用 .so库中的 JNI_OnLoad()函数来注册jni interface. Native 程序 实现了 JAVA 到 C++ 代码的Bridge 功能。 TestNativeApi.java 的代码如下: package com.me.test; import android.util.Log; public final class TestNativeApi { static { try { System.loadLibrary("itest_jni"); } catch (UnsatisfiedLinkError e) { Log.d("itest_jni", "itest jni library not found!"); } } /** * This class is uninstantiable. */ private TestNativeApi() { // This space intentionally left blank. } public native static int apiFunction(); } 1.2 修改Android 的Makefile(frameworks/base/core/jni/Android.mk), 通过Makefile 函数 BUILD_JAVA_LIBRARY 将TestNativeApi.java编译成jar. # Build com.me.test.jar # ============================================================ test_dirs := \ ./test/java/com/me/test test_src_files := $(call all-java-files-under,$(cm_dirs)) # ==== the library ========================================= include $(CLEAR_VARS) LOCAL_SRC_FILES := $(test_src_files) LOCAL_NO_STANDARD_LIBRARIES := true LOCAL_JAVA_LIBRARIES := core framework LOCAL_MODULE := com.me.test include $(BUILD_JAVA_LIBRARY) 1.3 此外还需要修改 framework/base/data/etc/platform.xml 添加. <library name= "com.me.test" file="/system/framework/com.me.test.jar" /> 使得jar包能够被应用程序link到. 2. 接着我们可以添加C++ 代码,来具体实现 Step1 中 定义的 JNI interface 。 2.1 添加 frameworks/base/core/jni/TestInternalApi.cpp 到Android 代码树,在这个C++类中可以调用底层的 C++/C函数控制硬件等。 其中 JNI_OnLoad()函数在.so被load的时候调用, test_TestInterAPI_Func() 函数则是Android 上层JAVA应用调用JNI apiFunction() 的时候具体运行的代码. #define LOG_TAG "itest_jni" #include <utils/misc.h> #include <utils/Log.h> #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include "scm_dbus_utils.h" #define INTERNALAPI_PKG_NAME "com/me/test/TestNativeApi" using namespace android; static jint test_TestInterAPI_Func(JNIEnv* env, jobject clazz) { jint ret = (jint)0; LOGD("call \"%s\"", __FUNCTION__); return ret; } /* * JNI registration. */ static JNINativeMethod gTestInterApiMethods[] = { { "apiFunction", "()I", (void *)test_TestInterAPI_Func } }; int register_com_me_test_TestInternalApiNative(JNIEnv *env) { return AndroidRuntime::registerNativeMethods(env, INTERNALAPI_PKG_NAME, gTestInterApiMethods, NELEM(gTestInterApiMethods)); } jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; LOGD("TestInteralApi JNI loaded"); if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { LOGE("GetEnv failed"); goto bail; } assert(env != NULL); if (register_com_me_test_TestInternalApiNative(env) < 0) { LOGE("TestInternalApi native registration failed"); goto bail; } result = JNI_VERSION_1_4; bail: return result; } 2.2 修改Android 的Makefile(frameworks/base/core/jni/Android.mk), 通过Makefile 函数 BUILD_JAVA_LIBRARY 将TestInternalApi.cpp编译成.so. include $(CLEAR_VARS) ifeq ($(TARGET_ARCH), arm) LOCAL_CFLAGS += -DPACKED="__attribute__ ((packed))" else LOCAL_CFLAGS += -DPACKED="" endif LOCAL_SRC_FILES:= \ TestInternalApi.cpp LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) LOCAL_SHARED_LIBRARIES := \ libandroid_runtime \ libnativehelper \ libcutils \ libutils \ libdvm LOCAL_MODULE:= libitest_jni include $(BUILD_SHARED_LIBRARY) endif 3. 重新编译Android 并且 install, 生成JNI .so 和 jar 包 /system/lib/libitest_jni.so /system/framework/com.me.test.jar 4. 为了在Eclipse 中编译和调试Android JNI, 需要安装 Android SDK 和ADT 如果使用Android 2.0.1/2.0.01 ,需要安装ADT-0.9.5.zip or up 4.1 安装 SDK 可以通过下面步骤 Set "Eclipse-->Window-->;Prefrences-->Android-->SDK Location" to Android SDK path 4.2 安装 ADT 可以通过下面步骤 Set "Eclipse-->Help > Software Updates..-->Add Site dialog-->click Archive" to the downloaded ADT-0.9.5.zip 5. 需要注意的是,因为我们是要测试JNI的实现,也就是Step2 中的.so,因此我们要将JNI Interface, 也就是Step1中的TestNativeApi.java 再编译一份Host Eclipse 可用的jar包 Eclipse -> File->New->;Project...->JAVA Project 添加 TestNativeApi.java 到 src/com/me/test/ 将 SDK 中的 android.jar 加入工程 的 “build library path” 编译成工后生成jar包, Export->java->jar ->com.me.test.jar 6. 最后是建立Android JUnit 测试工程,通过在Host上调用Step5的jar包(JNI Interface), 最终通过ADB 与Step2 生成的运行在Target 上JNI 实现通信来实现Debug. Eclipse -> File->New->;Project...->Android Test Project 6.1 添加 InternalApiAllTest.java (这是所有JUnit 共通的,可以直接拷贝) package com.me.internalapitest; import junit.framework.Test; import junit.framework.TestSuite; import android.test.suitebuilder.TestSuiteBuilder; /** * A test suite containing all tests for my application. */ public class InternalApiAllTest extends TestSuite { public static Test suite() { return new TestSuiteBuilder(AllTests.class).includeAllPackagesUnderHere().build(); } } 6.2 添加 InternalApiNativeTest.java (这是实际测试Case) package com.me.internalapitest; import junit.framework.Assert; import com/me/test/TestNativeApi; import android.test.InstrumentationTestCase; public class InternalApiNativeTestextends InstrumentationTestCase { protected void setUp() throws Exception { super.setUp(); } protected void tearDown() throws Exception { super.tearDown(); } public void testEnableSystem() throws Throwable { int result = InternalApiNativeTest.apiFunction(0); Assert.assertTrue(result == 0); } } 6.3 修改 InternalApiNativeTest 工程属性 将Step 5中 生成的 com.me.test.jar 到 Java build library path 7 . 代码全部添加完毕,现在就开始Debug 了。 7.1 登陆 Android board, 通过下面方法使目标板上 adbd 使用socket 端口而不是默认的usb口 #rm /dev/android_adb #rm /dev/android_adb_enable #setprop persist.service.adb.enable 1 #setprop service.adb.root 1 #setprop ctl.stop adbd #setprop ctl.start adbd 7.2. 因为 Host 端 Eclispe 也会启动ADB server, 而这个server 指向了Android Emulator, 所以需要先推出 Eclipse and 并先杀死所有 adb 进程 #ps aux | grep adb | grep -v grep #kill -9 <ADB_PID> 7.3. 接着 在Host 上再次开启 ADB server, #export ADBHOST=<ANDROID_BB_IP_ADDRESS> #export ADB_TRACE=adb #adb nodaemon server 如果在终端中看到下面的信息,就表明 这个时候 ADB server 指向了 Android 的开发板 ... parse_banner: device:: setting connection_state to CS_DEVICE adb: online ... 这时候可以在另外一个终端中ADB Shell登陆到Android 开发板 #export ADBHOST=<ANDROID_BB_IP_ADDRESS> #adb shell 7.4. 设置Android Junit 环境 #export ADBHOST=<ANDROID_BB_IP_ADDRESS> #<ECLISPE_PATH>/eclipse 选择 "Run-->Run Configuration-->Android JUnit Test", 选择"New Launch configuration" 在 "Test" tab, 选中"run all tests in the selected project, or package" 和 "InternalApiNativeTest" 在 "Target" tab, 选中 "Deployment Target Selection Mode" 的选项 "Manual" 7.5. 最后运行 JUnit test runner 在Step 7.3 生成的 ADB登陆终端中 # logcat 再在eclipse 选中菜单 "Run-->Run as-->Android jUnit Test" and 并使用Step 7.4 中生成的配置。 就可以看到 Eclipse 中的JUnit 显示测试结果。 并且在运行logcat 的Android 终端,打印出了frameworks/base/core/jni/TestInternalApi.cpp 中log信息 For other information about android jni, we can refer to this article http://android./JNIExample/ |
|