转帖:Android 远程调试 JNI 实现

标签: android test java 工程 build 2010-04-04 20:56

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/

转自:http://abandedknight.blog.sohu.com/147638999.html

更多相关文章

  1. C语言函数以及函数的使用
  2. android百度地图标记点代码
  3. AndTerm - Android super terminal- Android超级终端
  4. Android使用代码模拟HOME键的功能
  5. Android近百个项目的源代码
  6. Android代码速查,写给新手的朋友们
  7. Java代码设置Android全屏

随机推荐

  1. 利用Shell脚本将MySQL表中的数据转化为js
  2. MySQL十进制转化为二进制、八进制、十六
  3. 打印出不能正常工作的SQL查询结果[重复]
  4. SQL Server2012-SSIS的包管理和部署
  5. 如何判断如下的sql语句是否被正确执行了
  6. 第 5 章 MySQL 备份与恢复
  7. mysql笔记02:source命令导入大数据速度慢
  8. Mac下使用brew搭建PHP7+nginx+mysql开发
  9. shared pool原理,有AWR报告,主要是library
  10. 要查询选修了所有课程的学生信息,怎样用sq