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.wooyd.org/JNIExample/

更多相关文章

  1. 【Android进阶】android:configChanges属性总结
  2. android 屏幕方向切换 锁定方向
  3. Android(安卓)framework Watchdog的监控过程
  4. AndroidMenifest.xml中android:sharedUserId="android.uid.syste
  5. React Native踩坑:集成到现有Android原生应用、RN与Android相互调
  6. Android(安卓)JNI使用方法
  7. Android进程so注入Hook java方法
  8. android知识点
  9. android中使用OpenCV之调用设备摄像头

随机推荐

  1. android列表为空时提示语
  2. android 权限库,拿来就能用
  3. android gmail send email
  4. Android(安卓)常用的SDCARD和内存操作
  5. Android之Spinner解析
  6. android检查sqlite数据库中是否存在某个
  7. Android逐帧动画的实现
  8. android 混淆 proguard
  9. Android关于图片处理,更改图片灰度
  10. Android检测电源状态