?./adb remount ?//使得文件系統可讀寫?
./adb push 8188eu.ko /system/lib/modules ?傳輸文件
調試真機:
需要知道usb的廠商和產品ID,然后添加udev規則(否則,linux中可能識別不到真機的USB)。可以利用lsusb查看VID
- SUBSYSTEM=="usb",?SYSFS{idVendor}=="04e8",?MODE="0666"?
- /etc/udev/rules.d/53-android.rules??
1.1 查看設備(包括模擬設備和真實設備)
- ?adb?devices?
1.2 進入目標板的shell
- adb?shell?
? ? 如果存在多個設備,需要以下命令?
- adb?shell?-s?+?設備名?
????進入shell之后,可以使用dmesg查看內核打印信息。
? ??這點在權限遇到問題時非常有用,內核打印可以直接看到gid和uid的問題。(筆者對內核底層比較熟悉,目前不清楚JAVA層會有什么相關提示)。android 遠程調試。例如:
- qtaguid:?ctrl_counterset(s?1?10106):?insufficient?priv?from?pid=3318?tgid=3260?uid=1000
- <6>[16058.466766]??qtaguid:?ctrl_counterset(s?0?10085):?insufficient?priv?from?pid=3318?tgid=3260?uid=1000
2.Android Studio 調試
? ? 筆者使用的2.1.2,集成的編譯環調試相當方便。
? ? 在Monitor中集成了logcat,而且直接過濾出調試app的LOG。
?
3.JNI相關配置
?3.1 下載NDK
? ? 建議直接下載,然后在Android Studio中直接配置。
? ? 配置的方式為:在local.properties中添加NDK的路徑?
- ndk.dir=D\:\\Android\\android-sdk\\android-ndk-r11c-windows-x86_64\\android-ndk-r11c?
3.2 build.gradle的defaultConfig配置添加
- ?ndk{
- ????????????moduleName?"YanboberJniLibName"
- ????????????ldLibs?"log",?"z",?"m"
- ????????????abiFilters?"armeabi",?"armeabi-v7a",?"x86"
- ????????}
?? ? moduleName是庫文件的名字(不含.so或dll后綴)
?? ? jni的目錄結構:
3.3 JNI接口的聲明和定義
3.3.1 C 中的聲明
- #ifdef?__cplusplus
- extern?"C"?{
- #endif
- ?
- JNIEXPORT?jboolean?JNICALL?native_sudo(JNIEnv?*env,?jobject?obj,?jstring?xmd);
- JNIEXPORT?jboolean?JNICALL?native_exit(JNIEnv?*env,?jobject?obj);
- #ifdef?__cplusplus
- }
- #endif
?? ??JNIEnv 從linux的本質上來講是本地線程的環境,JNIEnv只在當前線程中有效。android 調試工具。指針不能從一個線程進入另一個線程,但可以在不同的線程中調用本地方法(這時,所傳遞的env是不同的)
? ??總結下:JNIEnv是與線程相關的變量,不同線程的JNIEnv彼此獨立。而JavaVM是虛擬機的JNI層的代表,在虛擬機進程中只有一個JavaVM,所以該進程的所有線程都可以使用這個JavaVM。
????簡單來講,就是庫函數的作用,具有良好可重載性。上一張圖片就簡單明了了:
3.3.2 使用JNINativeMethod注冊到線程環境
JNINativeMethod定義如下:
- static?JNINativeMethod?methods[]?=?{
- ??????{"sudo","(Ljava/lang/String;)Z",(void*)native_sudo},
- ??????{"nexit","()Z",(void*)native_exit},
- };
????native_sudo是jni層定義的函數。Android jni。
? ? sudo是JAVA層調用的函數。
? ??(Ljava/lang/String;)Z是函數傳遞參數和返回參數,多個參數使用";"進行分割。括號里的是形參,括號外的是返回值
? ? 這里的參數表示,后續作下補充。
? ??注:該結構體,第二個參數的分號漏掉,會導致無法找到JNI函數。android權限處理、
?
????注冊的過程直接上代碼了,這里可以直接套用:
- static?int?registerNativeMethods(JNIEnv*?env?,?const?char*?className?,?JNINativeMethod*?gMethods,?int?numMethods)
- {
- ????jclass?clazz;
- ????clazz?=?(*env)->FindClass(env,?className);
- ????if?(clazz?==?NULL)
- ????{
- ????????return?JNI_FALSE;
- ????}
- ?
- ????if?((*env)->RegisterNatives(env,?clazz,?gMethods,?numMethods)?<?0)
- ????{
- ????????return?JNI_FALSE;
- ????}
- ?
- ????return?JNI_TRUE;
- }
- ?
- //自定義函數
- static?int?registerNatives(JNIEnv*?env)
- {
- ????const?char*?kClassName?=?"io/github/yanbober/ndkapplication/NdkJniUtils";//指定要注冊的類
- ????return?registerNativeMethods(env,?kClassName,?methods,??sizeof(methods)?/?sizeof(methods[0]));
- }
- ?
- JNIEXPORT?jint?JNICALL?JNI_OnLoad(JavaVM*?vm,?void*?reserved)
- {
- ????LOGD("customer---------------------------JNI_OnLoad-----into.\n");
- ????JNIEnv*?env?=?NULL;
- ????jint?result?=?-1;
- ?
- ????//test();
- ?
- ????if?((*vm)->GetEnv(vm,?(void**)?&env,?JNI_VERSION_1_4)?!=?JNI_OK)
- ????{
- ????????return?-1;
- ????}
- ????assert(env?!=?NULL);
- ?
- ????if?(!registerNatives(env))
- ????{
- ????????return?-1;
- ????}
- ?
- ????return?JNI_VERSION_1_4;
- }
?3.3.3 JAVA層的定義
- public?class?NdkJniUtils?{
- ?
- ????public?native?boolean?sudo(String?cmd);
- ????public?native?boolean?nexit();
- ?
- ????static?{
- ????????System.loadLibrary("YanboberJniLibName");
- ????}
- }
?? ? 這里使用了類封裝。使用時,New一個NdkJniUtils即可調用JNI函數。
? ? ?函數使用native聲明之后,JAVA鏈接器會認為這個函數時外部函數,因此沒有在JNI層作相關定義,JAVA項目工程也是可以編譯通過的。
?????注:loadLibrary需要與之前build.gradle 中ndk字段聲明的名字相同。android 無線adb調試?
3.3.4 不使用JNINativeMethod的方法
?不使用JNINativeMethod的方法時,函數名定義的名稱必須按照規定的格式,相對比較復雜。個人并不喜歡這樣定義。
? 以前作的筆記,直接copy了(需要使用javah工具):
?確認javah生成頭文件的工具能否使用。如果不能,需要確認環境變量。android調試?
? 使用方法:
? 在聲明好native函數之后,進行build。
?然后以build好的class,利用javah生成頭文件,格式如下
- javah?-d?[dest?dir]?-classpath?[debug?dir]?[class?name]
-d: 頭文件存放的目錄。個人選擇main下的目錄(\helloworld\app\src\main\java),最好創建新目錄,用于存放native定義(如jni目錄),這樣可以在項目路徑上看到。
-classpath : 類存放的路徑;(\helloworld\app\build\intermediates\classes\debug)
[classname]:及之前聲明了native函數的類
?
當然如果感覺比較麻煩,在debug目錄使用相對路徑創建.h文件,然后將文件復制到main目錄。android 7、
?
然后,在-d的目錄下創建.c文件,對native函數作具體的定義。