开发者社区> 古镇月影> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

NDK开发历程(一):android native code的调试方法

简介: 引用:http://www.cnblogs.com/ychellboy/archive/2013/02/22/2922683.html   使用NDK在android上做开发是一件“痛并快乐着”的差事,之所以“快乐”是因为可以将一些原有的C/C++库直接移植到android上,而不需要用java再开发一套功能相同的库。
+关注继续查看

引用:http://www.cnblogs.com/ychellboy/archive/2013/02/22/2922683.html

  使用NDK在android上做开发是一件“痛并快乐着”的差事,之所以“快乐”是因为可以将一些原有的C/C++库直接移植到android上,而不需要用java再开发一套功能相同的库。然而这同时也是一件“痛苦”的事件,因为android本身是裁减过的linux,好些system call不能使用,另外由于没有采用glibc(用的是Bionic libc,原因见wiki),好些函数所在的头文件位置也有变化,这都给移植工作带来困难。更为坑爹的是一些函数在头文件里能找到定义在具体库里确没有实现(比如:pthread_mutex_timedlock)。

    android native开发在编译链接阶段会遇到上述“惨痛”经历,但更为痛苦的是好不容易变成可执行文件,一运行就crash没有任何信息。遇到这种情况,在排除了代码有低级错误的情况后,最终只能想办法做debug。(本文余下篇幅在不特殊注明的情况下都是指使用NDK在android上做native code的开发)。

    在android上NDK开发的程序进行查错主要有两种方法:

(1)使用log进行查错:在程序源代码上加log,根据log信息来排查错误。这种方式应该是最为常用的,因为其普适性很高。不过作为在VxWorks上移植过网络库的苦逼,深知用log排错的效率是多么的低,特别是在排查底层库时。而遇到多线程的程序,log排错是多么的无力。

(2)使用ndk-gdb调试程序:用过gdb的都知道它多么的强大,但是想要使用ndk-gdb需要做很多的配置,还会碰到很多坑,因此想真正使用起来也不是件容易的事(毕竟是开源项目,和VxWorks这种高富帅是没法比的)。

    本文主要介绍如何配置使用ndk-gdb进行debug,所使用android-ndk-r8d/samples/hello-jni作为入口调用一个static library。 ——  Here we go!

 

一、开发环境

1. ubuntu 12.04 x86_64

2. eclipse 3.7(只是为了方便启动android模拟器)

3. android NDK r8d

4. android SDK 2.2 ~ 4.2

5. ant (打包程序使用)

    在windows环境下可以配置cygwin来实现ndk-gdb,本人在windows上使用相同方法也达到了效果,对cygwin的配置这里不再讨论,有疑问可以找google老师。

 

二、准备阶段

    1. 下载linux平台的NDK,并解压到相应目录。这里需要注意的是:虽然google网站上写着NDK for Linux 32/64-bit(x86),但是ndk中的一些工具(比如NDK自带的awk,make,sed)在64bit的ubuntu上并不能直接运行,因为这些工具是32bit的程序,需要32bit的运行时库。解决方法是:sudo apt-get install libc6-i386, sudo apt-get install lib32asound2 lib32z1 lib32stdc++6 lib32bz2-1.0  安装这些常用的32位库。如果是CentOS则需要:yum install libgcc.i686 yum install glibc-static.i686 yum install glibc-devel.i686

    2. 下载SDK,在下载页面的”DOWNLOAD FOR OTHER PLATFORMS“ –>“ADT Bundle”找到对应的版本下载,并解压到相应的目录。这时SDK下的platforms会有最新版本的android,下载历史版本的android就要使用tools下的工具:./android list sdk 根据列举出来的编号执行如下: ./android update sdk –t 1 –u 则更新编号是1的包。使用android update把所需要的历史版本都下载下来。

    3. 根据实际情况在~/.profile(或~/.bash_profile)中设置如下环境变量,设置完毕后执行source ~/.profile使之生效:

# ---- NDK ---- 
NDK_ROOT=~/mysoftware/NDK/android-ndk-r8d 
PATH=$PATH:$NDK_ROOT 
export NDK_ROOT

# ---- android-SDK ---- 
ANDROID_SDK_ROOT=~/mysoftware/SDK/adt-bundle-linux-x86_64/sdk 
PATH=$PATH:$ANDROID_SDK_ROOT 
export ANDROID_SDK_ROOT

# ---- adb ---- 
ADB_PATH=~/mysoftware/SDK/adt-bundle-linux-x86_64/sdk/platform-tools 
PATH=$PATH:$ADB_PATH

# ---- tools/android ---- 
PATH=$PATH:~/mysoftware/SDK/adt-bundle-linux-x86_64/sdk/tools

export PATH

 

三、修改hello-jni

    由于项目使用c++编程,做这个实验的时候就将jni/hello-jni.c 改为hello-jni.cpp,代码如下:

   1: #include <string.h>
   2: #include <jni.h>
   3: #include <unistd.h>
   4: #include "shared/thread.h"
   5:  
   6: /* This is a trivial JNI example where we use a native method
   7:  * to return a new VM String. See the corresponding Java source
   8:  * file located at:
   9:  *
  10:  *   apps/samples/hello-jni/project/src/com/example/hellojni/HelloJni.java
  11:  */
  12:  
  13: using namespace shared;
  14:  
  15: extern "C"  {
  16:  
  17: void* StartThread(void* obj)
  18: {   
  19:     return NULL;
  20: }   
  21:  
  22: jstring
  23: Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
  24:                                                   jobject thiz )
  25: {       
  26:     volatile int bGo = 0;
  27:     while(!bGo) {
  28:         sleep(1);
  29:     }   
  30:     
  31:     Thread mythread(&StartThread, NULL);
  32:     mythread.Start();
  33:     
  34:     return env->NewStringUTF("Hello from JNI !");
  35:     //return (*env)->NewStringUTF(env, "Hello from JNI !");
  36: }   
  37:  
  38: }

    注意需要用extern “C”{ } 把Java_com_example_hellojni_HelloJni_stringFromJNI函数包起来,while (!bGo)是为了方便调试,因为ndk-gdb会先把程序run起来后再attach上去,这里需要一个while让程序等一会。上述代码中的Thread类是在libshared.a的静态库中,因此需要修改hello-jni目录下的jni/Android.mk文件。如下:

   1: LOCAL_PATH := $(call my-dir)
   2:  
   3: include $(CLEAR_VARS)
   4: LOCAL_MODULE := shared
   5: LOCAL_SRC_FILES := ../shared/obj/local/armeabi/libshared.a
   6: LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/shared
   7: include $(PREBUILT_STATIC_LIBRARY)
   8:  
   9: include $(CLEAR_VARS)
  10: LOCAL_MODULE    := hello-jni
  11: LOCAL_SRC_FILES := hello-jni.cpp
  12: LOCAL_STATIC_LIBRARIES := shared
  13: LOCAL_C_INCLUDES := $(LOCAL_PATH)/../
  14:  
  15: include $(BUILD_SHARED_LIBRARY)

    红色部分为添加或修改项,编译前需要在环境变量C_INCLUDE_PATH中加入jni.h的路径,比如:

   1: C_INCLUDE_PATH=$C_INCLUDE_PATH:~/mysoftware/NDK/android-ndk-r8d/platforms/android-8/arch-arm/usr/include
   2:  
   3: export C_INCLUDE_PATH

PS:libshared.a在build时需要加NDK_DEBUG=1的参数,即:ndk-build NDK_DEBUG=1,这么编译才能带上debug信息。

 

四、万事俱备

1. shell进入ndk/samples/目录,运行android update project --path hello-jni,生成build.xml用于apk打包。(也可以在hello-jni目录里运行:android update project -t 1 -p . --subprojects)

2. 进入ndk/samples/hello-jni,修改AndroidManifest.xml文件

   1: <application android:label="@string/app_name"

2: android:debuggable="true">

3. 运行ndk-build

4. 运行ant debug

5. 启动android的模拟器(可以从eclipse启动)

6. 运行adb install –r bin/HelloJni-debug.apk

7. 运行ndk-gdb –start 开始debug,后续和使用gdb一样

8. 需要图形化界面进行debug,可以参考[2]

 

    几点重要说明:

1. ndk-gdb用的是client/server形式对目标机器进行debug, gdb 调试器 与 gdbserver 的关系,就是 gdb 与 stub的关系,如下图所示[3] :

image

2. ndk-gdb最坑爹的是:gdb和gdbserver的版本必须是匹配的才能debug:

    每一个模拟器在system/bin下都有gdbserver,这些gdbserver是和模拟器本身的android版本有关的,而下载的NDK的ndk-gdb一般都是最新的gdb,因此gdb和gdbserver的版本常常匹配不了。这时需要把对应版本的gdbserver push到emulator上,然后指定./gdbserver,必须指定“./”因为在linux下默认优先查找system目录。

 

 

References:

[1] 使用eclipse/ndk-gdb对java/native code联合调试

[2] Eclipse+CDT+GDB调试android NDK程序

[3] ndk-gdb对java/native code联合调试

[4] 使用eclipse/ndk-gdb对java/native code联合调试

[5] 把hello-jni的.c后缀改成.cpp后出错

 
 
分类: Android开发

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
react-native run-android的输出
react-native run-android的输出
18 0
React Native Mac 下打包Android APK
打包的时候遇到了 好多坑 这里记录下~ 主要步骤: 1.android keystore签名的生成 gradle mac下环境变量的配置 3.android studio中的gradle配置。
2220 0
android中ndk的开发
前言(其实是吐槽) 这是我看(android应用安全防护和逆向分析)遇到的第一个坑了,在章节2.1和2.2里,虽然作者很贴心的给了步骤教你如何搭建ndk的开发环境,但是,我要说的是,如果按照作者在2.1.2的五个步骤按部就班的来,你绝对!不可能!完成! 主要的原因我就不再分析了,大约就是少了一堆乱七八糟的说明和步骤,这里我重新写一遍ndk开发相关。
1045 0
React Native工程修改Android包名
默认初始化的React Native工程,生成Android工程的时候,包名默认是React Native工程的名字,跟一般Android工程com.company.xxx不一样。 这时候就需要手动修改Android工程里面的包名信息: 如下: 首先修改React Native目录下的MainActivity.
801 0
GDB在线调试Android Framework Native C/C++代码
一、准备工作 1、下载并编译Android系统源码 这里比较灵活,可以下载公司内部机型的代码,也可以下载原生AOSP的代码 环境配置参考 https://source.
2605 0
Android进阶之NDK开发入门
最近一直在练车,晒的是好黑好黑啊,好久没写博客了,趁着中午有时间,赶紧写一篇,写完就得骑着我的宝马电瓶车去驾校学车,累死哦。 为了满足as和ec的用户,我两种IDE都讲,好久没水了,装装X。 首先,得做好开发准备,下载好NDK包,as用户呢,可以在setting–&gt;Android SDK里面找到,如下图: 可以看看自己的NDK是否安装了,如果没安装就勾选,并
1445 0
方便android开发网站:
可以通过输入包名或者Google Play地址消灾google市场的应用 http://apps.evozi.com/apk-downloader/   16进制转常用的10进制 http://www.
467 0
android 之ndk开发
<p><span style="font-size:24px; color:#FF0000">1、Android NDK简介</span></p> <p>NDK全称为native development kit本地语言(C&amp;C++)开发包。而对应的是经常接触的Android-SDK,(software development kit)软件开发包(只支持java语言开发)。</p>
1421 0
android 之ndk开发
1、Android NDK简介 NDK全称为native development kit本地语言(C&amp;C++)开发包。而对应的是经常接触的Android-SDK,(software development kit)软件开发包(只支持java语言开发)。 简单来说利用NDK,可以开发纯C&amp;C++的代码,然后编译成库,让利用Android-SDK开发的Java程序调用。ND
913 0
+关注
1699
文章
3
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载