董偉巍
(武漢郵電科學(xué)研究院 湖北 武漢 430000)
JNI技術(shù)在網(wǎng)絡(luò)交互中的應(yīng)用
董偉巍
(武漢郵電科學(xué)研究院 湖北 武漢430000)
Android是一款運(yùn)行在開放的Linux內(nèi)核之上的操作系統(tǒng),其上層應(yīng)用程序采用Java開發(fā)語言,底層核心類庫采用C/C++語言編寫,開發(fā)者能夠非常便捷的使用Android SDK調(diào)用豐富的API,實(shí)現(xiàn)各種功能。不僅如此,Android還支持跨平臺(tái)跨語言操作,通過JNI技術(shù)可以方便的調(diào)用使用其他語言編寫的程序,滿足各種不同的開發(fā)需求。
Android開發(fā);JNI技術(shù);跨平臺(tái);NDK
在移動(dòng)開發(fā)如火如荼的今天,Android作為目前市場(chǎng)占有率最高的智能手機(jī)操作系統(tǒng),自然是其中的佼佼者,其開發(fā)市場(chǎng)廣闊,勢(shì)如破竹,前景一片光明。Android系統(tǒng)架構(gòu)采用軟件疊層的方式進(jìn)行系統(tǒng)構(gòu)建,從上至下依次為應(yīng)用程序?qū)?、?yīng)用程序框架層、系統(tǒng)運(yùn)行庫層和以及Linux內(nèi)核層[1]。這種構(gòu)架方式使得層與層之間相對(duì)獨(dú)立,當(dāng)某一層發(fā)生了變化時(shí),其它層受到的影響相對(duì)較小。Android上層的應(yīng)用層和框架層都是使用Java語言,而系統(tǒng)運(yùn)行庫層和Linux內(nèi)核層則是使用C/C++編寫的,所以上層Java要調(diào)用底層的C/C++函數(shù)庫必須通過Java的JNI技術(shù)來實(shí)現(xiàn)[2]。
JNI即Java Native Interface,通過JNI技術(shù)可以實(shí)現(xiàn)Java與其他語言(常見的有C、C++)的交互。JNI是完善Java功能的一個(gè)重要組成部分,JVM兼容了各種操作系統(tǒng)的差異性使用Java程序可以跨平臺(tái)運(yùn)行,另一方面JNI提供了Java程序與操作系統(tǒng)和相關(guān)功能函數(shù)的交互接口使得Java功能更全面[3]。
JNI技術(shù)主要應(yīng)用在以下幾個(gè)方面:
1)在程序?qū)?shí)時(shí)性要求高或?qū)Τ绦蜻\(yùn)算性能要求特別高時(shí),可使用更底層的語言(如匯編、C和C++)來實(shí)現(xiàn)功能,然后在Java中調(diào)用;
2)在已有現(xiàn)成的用其他語言編寫的完整功能或者模塊時(shí),使用Java直接調(diào)用;
3)在涉及Java標(biāo)準(zhǔn)平臺(tái)所不具備的依賴操作系統(tǒng)的特性時(shí),使用JNI技術(shù)來實(shí)現(xiàn)。
圖1 JNI調(diào)用過程
JNI的調(diào)用過程可以抽象為一個(gè)代理模型來描述如圖 1所示,中間的 JNI-stub扮演著代理的角色,用來加載其他語言的動(dòng)態(tài)庫,聲明Native接口方法;
為了與底層語言對(duì)接,通過 Javah生成頭文件,使用底層語言編寫頭文件中函數(shù)的代碼實(shí)體,實(shí)現(xiàn)各種所需的功能,這就是最右邊native,即被代理方的實(shí)體;
同時(shí),聲明過的Native接口方法對(duì)其他Java類(圖1左邊部分)即客戶端開放,對(duì)于其他Java類來說JNI類可以通過簡(jiǎn)答操作,直接使用,與調(diào)用其他Java類一樣方便。
JNI開發(fā)需要用到NDK即Native Development Kit,下載Android NDK。下載地址為:http://developer.android.com/tools/ sdk/ndk/index.html下載后解壓縮到工作目錄。由于NDK開發(fā)大都涉及到C/C++在GCC環(huán)境下編譯、運(yùn)行,所以在Windows環(huán)境下,需要用Cygwin模擬Linux編譯環(huán)境[4]。
下載并安裝Cygwin,安裝好之后運(yùn)行安裝目錄下的“Cygwin.bat”,第一次運(yùn)行時(shí),它會(huì)自動(dòng)創(chuàng)建用戶信息,用戶信息存放在“.Cygwinhome”中。在運(yùn)行“Cygwin.bat”打開的命令行窗口輸入:“cygcheck-c cygwin”命令,會(huì)打印出當(dāng)前Cygwin的版本和運(yùn)行狀態(tài),如果status是ok的話,則cygwin運(yùn)行正常。分別輸入:“make-v”和,“gcc-v”命令如果檢測(cè)成功,會(huì)有make和gcc相關(guān)版本信息打印出來。
完成后開始配置NDK工作的環(huán)境變量,找到cygwin的安裝目錄,找到一個(gè)home<用戶名>.bash_profile文件,打開 bash_profile文件,添加 NDK=/cygdrive/<盤符 >/<android ndk目錄>例如:
NDK=/cygdrive/e/android-ndk-r5
export NDK
然后保存,打開 cygwin,輸入cd$NDK,若輸出上面配置的 /cygdrive/e/android-ndk-r5信息,則表明環(huán)境變量設(shè)置成功了。
3.1使用JNI的原因
網(wǎng)絡(luò)交互涉及多種底層網(wǎng)絡(luò)參數(shù),硬件參數(shù)的獲取,網(wǎng)絡(luò)數(shù)據(jù)的自定義處理等。Java是高級(jí)語言,對(duì)于底層的操作效率較低,而C/C++在這些領(lǐng)域都已經(jīng)有了比較成熟的解決方案。通過JNI技術(shù)我們可以很方便的在Android程序里使用這些成熟的解決方案,讓它為我們的應(yīng)用需求進(jìn)行服務(wù),
3.2Java應(yīng)用層
1)載入已經(jīng)編譯好的本地*.so庫文件
這段代碼說明程序開始運(yùn)行時(shí)就會(huì)加載ANKOclient,static區(qū)聲明的代碼會(huì)先于onCreate方法執(zhí)行。如果程序中使用到多個(gè)庫,例如還有一個(gè)P2pClient庫 (完整的名字是p2pclient.so),并且P2pClient不是你應(yīng)用程序的入口,那么p2pclient庫會(huì)在第一次使用P2pClient時(shí)候加載。
2)定義各需要調(diào)用的函數(shù)(這里只列舉部分函數(shù))
從程序中可以看到在聲明這兩個(gè)方法時(shí)使有到 native關(guān)鍵字,native表明這兩個(gè)方法是本地方法,也就是說這兩個(gè)方法是通過本地代碼(C/C++)實(shí)現(xiàn)的,而在Java代碼中僅僅是聲明。用eclipse編譯該工程,會(huì)生成相應(yīng)的.class文件,必須在生成.h文件之前編譯工程,因?yàn)樯?h文件需要用到相應(yīng)的.class文件。
3.3編寫頭文件
利用Javah生成相應(yīng)的.h文件,根據(jù).h文件編寫相應(yīng)的C/C++代碼[5]。首先在工程目錄下建立一個(gè)JNI文件夾,進(jìn)入此文件夾并輸入以下命令:
Javah-classpath bin-d jni libp2pclient
其中-classpath bin:表示類的路徑,-d jni:表示生成的頭文件存放的目錄,libp2pclient則是完整類名。此頭文件不需要用戶編譯,直接供其它C、C++程序引用。以下是生成的頭文件的部分內(nèi)容:
從上面的代碼中可以看到所聲明的函數(shù)名都比較長(zhǎng),不過它們的命名都是有規(guī)律的,完全是按照:Java_pacakege_class_mathod的形式來命名的。
3.4底層文件的編寫
編寫底層功能實(shí)現(xiàn)文件,需要導(dǎo)入剛剛生成的libp2pclient.h。
#include"libp2pclient.h"然后開始編寫函數(shù)實(shí)體,實(shí)現(xiàn)頭文件中的各個(gè)方法,完成需求的功能,以下為函數(shù)實(shí)體部分內(nèi)容:
此函數(shù)實(shí)現(xiàn)了硬件參數(shù)查詢的功能,返回值為一個(gè)結(jié)構(gòu)體,其中包括mac地址、通道數(shù)、是否支持拼接流在內(nèi)的三項(xiàng)內(nèi)容;
實(shí)現(xiàn)網(wǎng)絡(luò)參數(shù)獲取的功能,返回網(wǎng)絡(luò)參數(shù)。
3.5編譯生成相應(yīng)的庫
將寫好的功能文件編譯成可供Java類調(diào)用的庫文件之前,首先要編寫Android.mk文件,以下逐條介紹mk文件中各個(gè)內(nèi)容及其作用。
一個(gè)Android.mk文件首先必須定義好LOCAL_PATH變量。它用于在開發(fā)樹中查找源文件。在這個(gè)例子中,宏函數(shù)‘my-dir',由編譯系統(tǒng)提供,用于返回當(dāng)前路徑 (即包含Android.mk file文件的目錄)。
CLEAR_VARS由編譯系統(tǒng)提供, 指定讓 GNU MAKEFILE清除許多除LOCAL_PATH外的LOCAL_XXX變量 (例如 LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_ STATIC_LIBRARIES,……)。這是非常必要的,因?yàn)樗械木幾g控制文件都在同一個(gè)GNU MAKE執(zhí)行環(huán)境中,所有的變量都是全局的。
編譯需要用到的所有庫文件,資源文件等等(這里只列舉部分)。
用來打印在c代碼里實(shí)現(xiàn)log打印。
編譯的目標(biāo)對(duì)象,LOCAL_MODULE變量必須定義,以標(biāo)識(shí)你在Android.mk文件中描述的每個(gè)模塊。名稱必須是唯一的,而且不包含任何空格。
編譯所包含的所有cpp文件(這里只列舉部分)。
7)include$(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY表示編譯生成共享庫,是編譯系統(tǒng)提供的變量,指向一個(gè)GNU Makefile腳本,負(fù)責(zé)收集自從上次調(diào)用 'include$(CLEAR_VARS)'以來,定義在LOCAL_XXX變量中的所有信息,并且決定編譯什么,如何正確地去完成。
完成Android.mk文件的編寫之后可以進(jìn)行*.so庫文件的生成了,這里我們使用NDK所提供的ndk-build腳本生成共享庫libp2pclient.so,其中l(wèi)ibp2pclient.so會(huì)自動(dòng)生成到libs/ armeabi/目錄下,這時(shí)我們之前在Java類中寫好的調(diào)用函數(shù)就可以實(shí)現(xiàn)功能了,最后在eclipse中刷新我們的工程[6],重新編譯生成apk,libp2pclient.so共享庫將一起打包在apk文件內(nèi)。
本文介紹了Android開發(fā)中JNI技術(shù)在網(wǎng)絡(luò)交互過程中的應(yīng)用,重點(diǎn)闡述了NDK環(huán)境的配置和JNI技術(shù)的實(shí)現(xiàn)。當(dāng)程序中用到了Java API不提供的特殊系統(tǒng)環(huán)境,而跨進(jìn)程操作又不能現(xiàn)實(shí)時(shí);當(dāng)訪問一些己有的本地庫,但又不想付出跨進(jìn)程調(diào)用如效率、內(nèi)存、數(shù)據(jù)傳遞方面的代價(jià)時(shí);當(dāng)Java程序中的一部分代碼對(duì)效率要求非常高,如算法計(jì)算、圖形渲染時(shí),使用JNI技術(shù)將是不可避免的。
[1]劉正偉,文中領(lǐng),張海濤.云計(jì)算和云數(shù)據(jù)管理技術(shù)[J].計(jì)算機(jī)研究與發(fā)展,2012(S1):26-31.
[2]周貴芳,方貴明.基于JMF的跨平臺(tái)視頻點(diǎn)播系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)應(yīng)用與研究,2007,24(4):230-236.
[3]Sylvain Ratabouil.Android NDK Beginner's Guide.Packt Publishing.2012.1.26.
[4]王家林,王家俊,王家虎.Android高級(jí)開發(fā)實(shí)戰(zhàn):UI、NDK與安全[M].北京:電子工業(yè)出版社,2013.
[5]蔣挺宇,王鵬,楊樹.基于中間語言的JNI泄漏檢查[J].計(jì)算機(jī)研究與發(fā)展,2013,52(4):898-906.
[6]Kaspersky.Mobile malware evolution part 5[EB/OL].2012. 02.28.
[7]劉康,王宣銀.基于單片機(jī)的以太網(wǎng)絡(luò)接入系統(tǒng)的實(shí)現(xiàn)及網(wǎng)絡(luò)性能分析[J].工業(yè)儀表與自動(dòng)化裝置,2014(1):33-35.
[8]陳宏希,鄒益民.基于Java的Jess功能函數(shù)擴(kuò)展方法[J].工業(yè)儀表與自動(dòng)化裝置,2015(1):65-69.
Application of JNI technology in the network interaction
DONG Wei-wei
(Wuhan Research Institute of postal and Telecommunications,Wuhan 430000,China)
Android is an operating system that runs on an open Linux kernel.The upper application of Android adopts the programming language of Java,and the underlying core library of it using C/C++language.Therefore,it's very convenient for developers to call various API by Android SDK to realize all kinds of functions.Besides,Android supports cross-platform and cross-language operation as well,so you can easily call any program written in other languages by JNI technology to meet a variety of developing needs.
Android development;JNI technology;cross-platform;NDK
TN915.2
A
1674-6236(2016)06-0125-03
2015-05-18稿件編號(hào):201505153
董偉?。?992—),女,湖北武漢人,工程師。研究方向:通信軟件。