C/C++中寫(xiě)的程序可以避開(kāi)JVM的內(nèi)存開(kāi)銷(xiāo)過(guò)大的相知合搅、處理高性能的計(jì)算牌柄、調(diào)用系統(tǒng)服務(wù)等畸悬,但是java調(diào)用jni空方法和java調(diào)用java方法相比,性能非常低的珊佣。所以一般只用來(lái)處理一些對(duì)運(yùn)算有要求蹋宦,或者需要對(duì)接口隱蔽的功能。
JNI 一般編寫(xiě)流程 其實(shí)就是為了避免一些錯(cuò)誤 用javah生成jni函數(shù)名咒锻,還是值得推薦使用的冷冗。驗(yàn)證過(guò),可以生成惑艇。比較使用的小技巧蒿辙。
javac src/com/example/com/enjoy/test/test.java -d ./bin
javah -jni -classpath ./bin -d ./jni com.example.com.enjoy.test.test
- apk crash 有l(wèi)og 可以定位拇泛,程序的anr 會(huì)在記錄在/data/anr/traces.txt mtk aee log也有。
但是NDK Crash 定位就很難了 思灌,容易出錯(cuò)的地方有 內(nèi)存地址訪問(wèn)錯(cuò)誤 使用野指針 內(nèi)存泄露 堆棧溢出 初始化錯(cuò)誤 類(lèi)型轉(zhuǎn)換錯(cuò)誤 數(shù)字除0(11/0) 等等
使用ndk-stack 進(jìn)行定位到行俺叭。
- 因?yàn)?Java 默認(rèn)使用 Unicode 編碼,而 C/C++默認(rèn)使用 UTF 編碼,所以在本地代碼中操作字符串的時(shí)候,必須使用合適的 JNI 函數(shù)把 jstring 轉(zhuǎn)換成 C 風(fēng)格的字符串。 JNI 支持字符串在 Unicode和 UTF-8 兩種編碼之間轉(zhuǎn)換,GetStringUTFChars 可以把一個(gè) jstring 指針(指向 JVM 內(nèi)部的 Unicode字符序列)轉(zhuǎn)換成一個(gè) UTF-8 格式的 C 字符串泰偿。
-調(diào)用完 GetStringUTFChars 之后不要忘記安全檢查,因?yàn)?JVM 需要為新誕生的字符串分配內(nèi)存空間,當(dāng)內(nèi)存空間不夠分配的時(shí)候,會(huì)導(dǎo)致調(diào)用失敗,失敗后 GetStringUTFChars 會(huì)返回 NULL,并拋出一個(gè) OutOfMemoryError 異常熄守。JNI 的異常和 Java 中的異常處理流程是不一樣的,Java 遇到異常如果沒(méi)有捕獲,程序會(huì)立即停止運(yùn)行。而 JNI 遇到未決的異常不會(huì)改變程序的運(yùn)行流程,也就是程序會(huì)繼續(xù)往下走 - 接口找不到
在Java中調(diào)用JNI接口時(shí)耗跛,出現(xiàn)異常裕照,察看日志,發(fā)現(xiàn)有如下錯(cuò)誤:
WARN/dalvikvm(422): No implementation found for native Lcom/whty/wcity/HelixPlayer;.setDllPath (Ljava/lang/String;)V
檢查了幾遍代碼调塌,Cpp中確實(shí)定義了這個(gè)接口晋南,而且仔細(xì)對(duì)照了Java的包名、類(lèi)名羔砾,確實(shí)沒(méi)有錯(cuò)誤负间,那為什么會(huì)出現(xiàn)這種問(wèn)題呢。后來(lái)突然想到蜒茄,JNI接口 都是以C的方式定義的唉擂,現(xiàn)在使用C++實(shí)現(xiàn),函數(shù)定義前是否需要加上extern "C"呢檀葛?為此定義了一個(gè)頭文件,在CPP文件中include該頭文件腹缩,頭文件加上如下代碼片斷:
ifdef __cplusplus
extern "C" {
endif
endif
...
ifdef __cplusplus
}
再次嘗試屿聋,調(diào)用成功!
- MTK flash tool 刷機(jī)問(wèn)題 ubuntu 下刷機(jī) 出現(xiàn)了異常藏鹊。
BROM ERROR : STATUS_ERR (-1073676287)
STATUS_BROM_CMD_SEND_DA_FAIL
chip mismatch MT0000
這幾個(gè)問(wèn)題 直接用ok機(jī)器的
/etc/udev/rules.d/ 目錄下文件全部替換即可
jni讀寫(xiě)文件 open 時(shí)候出錯(cuò) fd 返回-1 文件節(jié)點(diǎn)權(quán)限是666
剛開(kāi)始以為是權(quán)限問(wèn)題润讥,chmod 666后發(fā)現(xiàn)還是不行使用java 文件流進(jìn)行讀寫(xiě) 發(fā)現(xiàn)讀是ok的
寫(xiě)時(shí)候出現(xiàn)異常 后面公司大神改了下驅(qū)動(dòng) 將模塊驅(qū)動(dòng)中映射的open函數(shù)直接返回0
還是不行 。
最后自己懷疑是selinux 問(wèn)題
我的avc 異常:
[ 138.125449] <6>.(6)[283:logd.auditd]type=1400 audit(1496479197.368:93): avc: denied { read write } for pid=3144 comm="m.enjoy.testjni" name="ttctl" dev="tmpfs" ino=11250 scontext=u:r:system_app:s0 tcontext=u:object_r:ttctl_device:s0 tclass=chr_file permissive=0
修改:
/alps/device/mediatek/common/sepolicy/system_app.te
+allow system_app ttctl_device:chr_file { read write ioctl open };
還沒(méi)驗(yàn)證 下周再驗(yàn)證吧盘寡。編譯實(shí)在是太慢了楚殿。
周一了周六遺留的問(wèn)題解決了看log很重要,但是ioctl 返回值-1剩下就要看驅(qū)動(dòng)了竿痰。
-在framework PowerManger中添加 接口脆粥,update-api 發(fā)現(xiàn)mmm但編譯之后 一直報(bào)方法未重寫(xiě),但實(shí)際已經(jīng)重寫(xiě)影涉,不明原因变隔,直接根目錄下全編一次就好了。
- 報(bào)checkJni錯(cuò)誤一般在jni映射函數(shù)中出錯(cuò)了蟹倾,比如返回類(lèi)型沒(méi)寫(xiě)對(duì)