Android NDK 開發(三)--常見錯誤錦集合Log的使用【轉】

來源:互聯網
上載者:User

標籤:hlist   sys   tor   添加   功能   build   亂碼問題   base   dma   

  轉載請註明出處:http://blog.csdn.net/allen315410/article/details/41826511 

        Android NDK開發經常因某些因素會出現一些意想不到的錯誤,很多時候調試這些錯誤的時候,顯得比調試Java代碼要複雜,一方面是導致錯誤的原因很多很雜,另一方面NDK開發涉及到C/C++代碼的編寫,很多程式員對此不熟悉。那麼這篇部落格就總結一下,在NDK開發中經常出現的一些問題,並且嘗試提供一些正確的解決方案,方便在開發時能夠快速定位到錯誤,更改錯誤,當然了,錯誤是多種多樣的,很難把所有的錯誤都總結出來,在這裡僅作為一個筆記吧,以後在NDK開發中發現一個錯誤或者解決一個錯誤後,我就在這裡記錄一下,日積月累,就不錯了!

常見錯誤及解決方案 1,Android.mk檔案不存在 錯誤描述:Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk  
                   /cygdrive/e/ndk/android-ndk-r10d/build/core/add-application.mk:199: *** Android NDK: Aborting...    。 停止。

解決方案:報這個錯誤就需要查看一下工程目錄下的jni目錄下,是否有Android.mk檔案,或者Android.mk檔案名稱是否輸入錯誤了。

 

2,Android.mk檔案配置出錯

錯誤描述:/cygdrive/e/ndk/android-ndk-r10d/build/core/build-shared-library.mk:23: *** Android NDK: Missing LOCAL_MODULE before including                                                                    BUILD_SHARED_LIBRARY in jni/Android.mk    。 停止。

解決方案:檢查Android.mk檔案配置資訊。Missing LOCAL_MODULE表明LOCAL_MODULE配置出錯,查看並修正。

 

3,C語言代碼有錯誤

錯誤描述:[armeabi] Compile thumb  : Hello <= Hello.c
                    jni/Hello.c: In function ‘Java_com_example_ndk_MainActivity_java_1From_1JNI‘:
                    jni/Hello.c:17:9: warning: division by zero [-Wdiv-by-zero]
                    int i=5/0;
                              ^
                    [armeabi] SharedLibrary  : libHello.so
                    [armeabi] Install        : libHello.so => libs/armeabi/libHello.so

解決方案:C語言報錯通常錯誤資訊很多,我們可以根據cygwin上的LOG定位到錯誤。

 

4,Java代碼中沒有找到C程式碼程式庫錯誤描述:AndroidRuntime(1171): java.lang.UnsatisfiedLinkError: Couldn‘t load Hello1 from loader dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ndk-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.example.ndk-1, /system/lib]]]: findLibrary returned null

解決方案:說明Java代碼在載入C程式碼程式庫的時候弄粗了C程式碼程式庫的名稱,請在java層中改正。

 

5,C代碼函數簽名錯誤

錯誤描述:java.lang.UnsatisfiedLinkError: Native method not found: com.example.ndk.MainActivity.java_From_JNI:()Ljava/lang/String;

解決方案:Native method not found。這個應該不難吧,一看就知道是C語言中的函數簽名出錯了。

 

6,ndk版本問題

錯誤描述:Android NDK: WARNING: APP_PLATFORM android-19 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml
                    [armeabi] Compile thumb  : Hello <= Hello.c
                    [armeabi] SharedLibrary  : libHello.so
                    [armeabi] Install        : libHello.so => libs/armeabi/libHello.so

解決方案:這隻是一個警告而已,不處理的話程式也照樣運行。導致這個警告的原因是當前ndk的版本>工程中minSdkVersion,想要去掉這個警告就將minSdkVersion支援的最小版本號碼改成ndk版本號碼一致,當然了這是愚蠢的做法,但是我們可以使用ndk的低版本編譯,也不太好。下面是個好的解決方案:

1,在工程目錄jni下建立一個新的檔案,檔案名稱是 Application.mk

2,在Application.mk檔案裡加上這樣的一句:

APP_PLATFORM := android-8

 

3,儲存工程,編譯一下,就看見這個警告沒有了。

 

7,使用javah命令產生函數簽名時,找不到class檔案

錯誤描述:錯誤: 無法訪問android.app.Activity
                              找不到android.app.Activity的類檔案

解決方案:這個錯誤的具體原因應該沒有找到對應的native方法所在的Java位元組碼檔案,但是我這裡確實路徑是正確,還是報錯了,很奇怪,不知道是不是Eclipse上的一個BUG。遇到這個問題時,可以這樣解決,既然切換到\bin\classes目錄下不行的話,那就切換到工程目錄\src目錄,再javah一下,這次居然產生了.h的標頭檔,不知道為什麼這樣,反正我測試的時候可行。

tip:獲得本地方法標頭檔 
jdk6.0:在Android工程的bin\classes目錄下執行:javah 包名+類名
jdk7.0:在Android工程的src目錄下執行:javah 包名+類名

 

8,中文亂碼問題

錯誤描述:ndk開發中經常會在C語言代碼中往Java代碼返回一個中文字串,偶爾在Java中調用的時候,程式結果會出現中文亂碼情況,或者更有甚者導致程式直接崩潰掉,查看Log日誌也是說明出現亂碼的情況。

解決方案:

         中文亂碼的原因是英文C語言檔案儲存的格式不是UTF-8的格式,或者整個工程都不是UTF-8的格式,因為C語言jni傳遞字串時採用的UTF-8編碼,這一點可以在(*env)->NewStringUTF(env, "hello jni!")看出,NewStringUTF(env,char*)這個方法說明返回的是UTF-8編碼形式的字串。所以我們在建立工程的時候,或者建立一個C語言代碼檔案的時候,需要指定工程編碼為UTF-8或者C語言代碼檔案的儲存格式是UTF-8。

 

9,編碼GBK的不可映射的字元

錯誤描述:編碼GBK的不可映射字元。

解決方案:引起這個錯誤的原因是使用javah時沒有指定java的編碼集,這種情況下編譯器自動根據windows預設的編碼(GBK)編譯,而Java支援UTF-8的編碼集。解決這個問題的方法是在javah命令執行時為編譯器指定一個編碼集,使用javah命令的參數-encoding 編碼集,

 

LOG日誌的使用

        上面列舉了一些ndk開發中經常會遇見的問題以及解決方案,但是唯獨沒有列出的,也是最常見的錯誤,就是C語言代碼中出現錯誤,這個不太好解決,而且出現的問題是各種各樣,具體情況具體對待。已知在使用Java開發Android程式時,Google為了方便程式員調試,在SDK中提供了LOG輸出功能,程式員用來輸出程式中的日誌使用。那麼慶幸的是,Google在NDK中也提供了類似的LOG機制,協助native層代碼錯誤的定位。下面就嘗試一下使用這個LOG機制。

       在ndk解壓目錄下platforms\android-8\arch-arm\usr\include\android有個log.h的標頭檔,這個log.h的標頭檔用來管理C語言代碼中的LOG輸出,代碼如下:

[cpp] view plain copy  print?
  1. #ifndef _ANDROID_LOG_H  
  2. #define _ANDROID_LOG_H  
  3.   
  4. #include <stdarg.h>  
  5.   
  6. #ifdef __cplusplus  
  7. extern "C" {  
  8. #endif  
  9.   
  10. /* 
  11.  * Android log priority values, in ascending priority order. 
  12.  */  
  13. typedef enum android_LogPriority {  
  14.     ANDROID_LOG_UNKNOWN = 0,  
  15.     ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */  
  16.     ANDROID_LOG_VERBOSE,  
  17.     ANDROID_LOG_DEBUG,  
  18.     ANDROID_LOG_INFO,  
  19.     ANDROID_LOG_WARN,  
  20.     ANDROID_LOG_ERROR,  
  21.     ANDROID_LOG_FATAL,  
  22.     ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */  
  23. } android_LogPriority;  
  24.   
  25. /* 
  26.  * Send a simple string to the log. 
  27.  */  
  28. int __android_log_write(int prio, const char *tag, const char *text);  
  29.   
  30. /* 
  31.  * Send a formatted string to the log, used like printf(fmt,...) 
  32.  */  
  33. int __android_log_print(int prio, const char *tag,  const char *fmt, ...)  
  34. #if defined(__GNUC__)  
  35.     __attribute__ ((format(printf, 3, 4)))  
  36. #endif  
  37.     ;  
  38.   
  39. /* 
  40.  * A variant of __android_log_print() that takes a va_list to list 
  41.  * additional parameters. 
  42.  */  
  43. int __android_log_vprint(int prio, const char *tag,  
  44.                          const char *fmt, va_list ap);  
  45.   
  46. /* 
  47.  * Log an assertion failure and SIGTRAP the process to have a chance 
  48.  * to inspect it, if a debugger is attached. This uses the FATAL priority. 
  49.  */  
  50. void __android_log_assert(const char *cond, const char *tag,  
  51.               const char *fmt, ...)      
  52. #if defined(__GNUC__)  
  53.     __attribute__ ((noreturn))  
  54.     __attribute__ ((format(printf, 3, 4)))  
  55. #endif  
  56.     ;  
  57.   
  58. #ifdef __cplusplus  
  59. }  
  60. #endif  
  61.   
  62. #endif /* _ANDROID_LOG_H */  

         上面的代碼看不懂也沒關係,我們只需要知道怎麼用就行了。

 

1,在C語言代碼中引用log.h的標頭檔,並且預定義LOG_TAG標記Tag名稱,預定義輸出規則:

2,用上面預定義的名稱定義LOG輸出的內容

 

[cpp] view plain copy  print?
  1. #include<stdio.h>  
  2. #include<jni.h>  
  3. #include"com_example_ndk_MainActivity.h"  
  4. #include <android/log.h>  
  5. #define LOG_TAG "System.out.c"  
  6. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)  
  7. #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)  
  8.   
  9. JNIEXPORT jstring JNICALL Java_com_example_ndk_MainActivity_javaFromJNI(  
  10.         JNIEnv* env, jobject obj) {  
  11.     return (*env)->NewStringUTF(env, "hello jni!");  
  12. }  
  13.   
  14. /* 
  15.  * Class:     com_example_ndk_MainActivity 
  16.  * Method:    java_From_JNI 
  17.  * Signature: ()Ljava/lang/String; 
  18.  */  
  19. JNIEXPORT jstring JNICALL Java_com_example_ndk_MainActivity_java_1From_1JNI(  
  20.         JNIEnv* env, jobject obj) {  
  21.   
  22.     LOGI("function called");  
  23.     LOGI("array init");  
  24.     char c1[3] = { ‘a‘, ‘b‘, ‘c‘ };  
  25.     char c2[2] = { ‘d‘, ‘e‘ };  
  26.     LOGI("array init finish");  
  27.     LOGI("copy array");  
  28.     strcat(c1, c2); //把c2的內容放在c1的後面,要求c1長度>c2長度  
  29.     LOGI("copy array finish");  
  30.   
  31.     return (*env)->NewStringUTF(env, "hello_jni__");  
  32. }  

上述的代碼中

[cpp] view plain copy  print?
  1. #include <android/log.h>  
  2. #define LOG_TAG "System.out.c"  
  3. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)  
  4. #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)  

是必須添加的,告訴編譯器這裡需要輸出LOG,LOG的TAG標記是“System.out.c”,並且預定義LOGD(...)代表Debug輸出,LOGI(...)代表Info輸出。然後在C語言主題代碼中就可以使用LOGD和LOGI了,傳遞字串就可以了,需要注意的是傳遞的字串要用英文字元,不支援中文。

 

3,在Android.mk檔案中配置LOG輸出

 

[html] view plain copy  print?
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4.   
  5. LOCAL_MODULE    := Hello  
  6.   
  7. LOCAL_SRC_FILES := Hello.c  
  8.   
  9. LOCAL_LDLIBS += -llog  
  10.   
  11. include $(BUILD_SHARED_LIBRARY)  

注意:就一句 LOCAL_LDLIBS += -llog 就行了,但是必須得加在 include $(BUILD_SHARED_LIBRARY) 之前。

 

4,重新編譯代碼,運行看看效果

        好了,我們在Logcat裡面過濾出來System.out.c的TAG,可以看到在輸出copy array之後程式停止了,說明LOGI("copy array");下面的strcat(c1, c2);出現了錯誤,這裡需要修改代碼中的錯誤,程式才能正確執行,是不是很方便啊?試試吧! 

Android NDK 開發(三)--常見錯誤錦集合Log的使用【轉】

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.