Android NDK 开发--常见错误锦集合Log的使用

努力尽今夕,少年犹可夸。这篇文章主要讲述Android NDK 开发--常见错误锦集合Log的使用相关的知识,希望能为你提供帮助。
  转载请注明出处:http://blog.csdn.net/allen315410/article/details/41826511 
          Android  NDK开发经常因某些因素会出现一些意想不到的错误,很多时候调试这些错误的时候,显得比调试Java代码要复杂,一方面是导致错误的原因很多很杂,另一方面NDK开发涉及到C/C++代码的编写,很多程序员对此不熟悉。那么这篇博客就总结一下,在NDK开发中经常出现的一些问题,并且尝试提供一些正确的解决方案,方便在开发时能够快速定位到错误,更改错误,当然了,错误是多种多样的,很难把所有的错误都总结出来,在这里仅作为一个笔记吧,以后在NDK开发中发现一个错误或者解决一个错误后,我就在这里记录一下,日积月累,就不错了!
常见错误及解决方法   1,android.mk文件不存在

Android NDK 开发--常见错误锦集合Log的使用

文章图片
  错误描述: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文件配置出错
Android NDK 开发--常见错误锦集合Log的使用

文章图片

错误描述:/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语言代码有错误
Android NDK 开发--常见错误锦集合Log的使用

文章图片

错误描述:[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代码库
Android NDK 开发--常见错误锦集合Log的使用

文章图片
错误描述: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代码函数签名错误
Android NDK 开发--常见错误锦集合Log的使用

文章图片

错误描述: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 开发--常见错误锦集合Log的使用

文章图片

错误描述: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 NDK 开发--常见错误锦集合Log的使用

文章图片

错误描述:错误: 无法访问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的不可映射的字符
Android NDK 开发--常见错误锦集合Log的使用

文章图片

【Android NDK 开发--常见错误锦集合Log的使用】错误描述:编码GBK的不可映射字符。
解决方法:引起这个错误的原因是使用javah时没有指定java的编码集,这种情况下编译器自动根据windows默认的编码(GBK)编译,而Java支持UTF-8的编码集。解决这个问题的方法是在javah命令执行时为编译器指定一个编码集,使用javah命令的参数-encoding 编码集,如图
Android NDK 开发--常见错误锦集合Log的使用

文章图片

 
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?
Android NDK 开发--常见错误锦集合Log的使用

文章图片
Android NDK 开发--常见错误锦集合Log的使用

文章图片
  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?
Android NDK 开发--常见错误锦集合Log的使用

文章图片
Android NDK 开发--常见错误锦集合Log的使用

文章图片
  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?
Android NDK 开发--常见错误锦集合Log的使用

文章图片
Android NDK 开发--常见错误锦集合Log的使用

文章图片
  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?
Android NDK 开发--常见错误锦集合Log的使用

文章图片
Android NDK 开发--常见错误锦集合Log的使用

文章图片
  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,重新编译代码,运行看看效果
Android NDK 开发--常见错误锦集合Log的使用

文章图片

        好了,我们在Logcat里面过滤出来System.out.c的TAG,可以看到在输出copy array之后程序停止了,说明LOGI("copy array"); 下面的strcat(c1, c2); 出现了错误,这里需要修改代码中的错误,程序才能正确执行,是不是很方便啊?试试吧! 

    推荐阅读