Android JNI remote debugging

來源:互聯網
上載者:User

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/

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.