android NDK编译问题,在将项目中的JNI部分编译时,报出了错误,不能成功生成SO文件,

android NDK编译问题,在将项目中的JNI部分编译时,报出了错误,不能成功生成SO文件,,第1张

其实android ndk上的编译说到底也就是交叉编译,只要配置好交叉编译工具链,使用原有的makefile也是可以编译出在android运行的c、c++程序的。以android-ndk-r4-crystax的ndk版本为例:编译器路径 android-ndk-r4-crystax/build/prebuilt/linux-x86/arm-eabi-440/bin名称前缀 arm-eabi-头文件目录 android-ndk-r4-crystax/build/platforms/android-3/arch-arm/usr/include库文件目录 android-ndk-r4-crystax/build/platforms/android-3/arch-arm/usr/lib你可以试一下上面的配置,如果编译链接都没有问题,可以adb push到android设备上运行看看,什么结果?有点崩溃,根本运行不起来,你也许想试试看android自带的ndk例子,确实是能够运行的,问题在哪儿呢?只是正确配置了编译器、头文件、库文件还不够,还需要配置编译、链接的参数,android例子中编译链接的参数是什么呢?你也许想深究一下android的makefile,可是不久你会发现那是更崩溃的事情,里面用了很多的make脚本函数。其实android的makefile是可以把执行的详细命令输出来的,只要make的时候加上V=1即可。可以看到确实带了很多参数编译参数:-fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -Wa,--noexecstack -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -DANDROID 链接参数:-nostdlib -Bdynamic -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -Wl,--no-undefined -Wl,-z,noexecstack -L$(PLATFORM_LIBRARY_DIRECTORYS) crtbegin_statico crtend_androido 这其中链接参数中的-Wl,-dynamic-linker,/system/bin/linker、crtbegin_statico、crtend_androido是最关键的,android使用了自己的进程加载器,并且自定义了c运行时的启动结束。难怪先前编译的进程启动不了。

①DEX加固:对DEX文件进行加壳防护,防止被静态反编译工具破解获取源码
②Unity3d脚本保护:对U3D脚本文件进行加壳保护,对DLL文件进行保护
③防调试器:防止通过使用调试器工具对应用进行非法破解
④SO加密保护:对SO里面的逻辑进行分析,保护Native代码不被逆向分析
⑤防二次打包:保护应用在被非法二次打包后不能正常运行
⑥内存防Dump保护:防止通过在内存中破解,从而获取源代码

正式开始这个话题之前,先简单介绍一下什么是NDK和JNI,部分内容来自网络
Android NDK是什么,为什么我们要用NDK?
Android NDK 是在SDK前面又加上了“原生”二字,即Native Development Kit,因此又被Google称为“NDK”。众所周知,Android程序运行在Dalvik虚拟机中,NDK允许用户使用类似C / C++之类的原生代码语言执行部分程序。NDK包括了:
•从C / C++生成原生代码库所需要的工具和build files。
•将一致的原生库嵌入可以在Android设备上部署的应用程序包文件(application packages files,即apk文件)中。
•支持所有未来Android平台的一些列原生系统头文件和库
为何要用到NDK?概括来说主要分为以下几种情况:
•代码的保护,由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。
•在NDK中调用第三方C/C++库,因为大部分的开源库都是用C/C++代码编写的。
•便于移植,用C/C++写的库可以方便在其他的嵌入式平台上再次使用。
Android JNI是什么?和NDK是什么关系?
Java Native Interface(JNI)标准是java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI是本地编程接口,它使得在 Java 虚拟机(VM) 内部运行的 Java 代码能够与用其它编程语言(如 C、C++和汇编语言)编写的应用程序和库进行交互 *** 作。
简单来说,可以认为NDK就是能够方便快捷开发so文件的工具。JNI的过程比较复杂,生成so需要大量 *** 作,而NDK就是简化了这个过程。
NDK的异常会不会导致程序Crash,NDK的常见的有哪些类型异常?
NDK编译生成的so文件作为程序的一部分,在运行发生异常时同样会造成程序崩溃。不同于Java代码异常造成的程序崩溃,在NDK的异常发生时,程序在Android设备上都会立即退出,即通常所说的闪退,而不会d出“程序xxx无响应,是否立即关闭”之类的提示框。
NDK是使用C/C++来进行开发的,熟悉C/C++的程序员都知道,指针和内存管理是最重要也是最容易出问题的地方,稍有不慎就会遇到诸如内存无效访问、无效对象、内存泄露、堆栈溢出等常见的问题,最后都是同一个结果:程序崩溃。例如我们常说的空指针错误,就是当一个内存指针被置为空(NULL)之后再次对其进行访问;另外一个经常出现的错误是,在程序的某个位置释放了某个内存空间,而后在程序的其他位置试图访问该内存地址,这就会产生一个无效地址错误。常见的错误类型如下:
•初始化错误
•访问错误
•数组索引访问越界
•指针对象访问越界
•访问空指针对象
•访问无效指针对象
•迭代器访问越界
•内存泄露
•参数错误
•堆栈溢出
•类型转换错误
•数字除0错误
NDK错误发生时,我们能拿到什么信息?
利用Android NDK开发本地应用的时候,几乎所有的程序员都遇到过程序崩溃的问题,但它的崩溃会在logcat中打印一堆看起来类似天书的堆栈信息,让人举足无措。单靠添加一行行的打印信息来定位错误代码做在的行数,无疑是一件令人崩溃的事情。在网上搜索“Android NDK崩溃”,可以搜索到很多文章来介绍如何通过Android提供的工具来查找和定位NDK的错误,但大都晦涩难懂。下面以一个实际的例子来说明,首先生成一个错误,然后演示如何通过两种不同的方法,来定位错误的函数名和代码行。
首先,看我们在hello-jni程序的代码中做了什么(有关如何创建或导入工程,此处略),看下图:在JNI_OnLoad()的函数中,即so加载时,调用willCrash()函数,而在willCrash()函数中, std::string的这种赋值方法会产生一个空指针错误。这样,在hello-jni程序加载时就会闪退。我们记一下这两个行数:在61行调用了willCrash()函数;在69行发生了崩溃。
下面来看看发生崩溃(闪退)时系统打印的logcat日志:
[plain] view plain copy
1
2 Build fingerprint: 'vivo/bbk89_cmcc_jb2/bbk89_cmcc_jb2:421/JOP40D/1372668680:user/test-keys'
3 pid: 32607, tid: 32607, name: xamplehellojni >>> comexamplehellojni <<<
4 signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000
5 r0 00000000 r1 beb123a8 r2 80808080 r3 00000000
6 r4 5d635f68 r5 5cdc3198 r6 41efcb18 r7 5d62df44
7 r8 4121b0c0 r9 00000001 sl 00000000 fp beb1238c
8 ip 5d635f7c sp beb12380 lr 5d62ddec pc 400e7438 cpsr 60000010
9
10 backtrace:
11 #00 pc 00023438 /system/lib/libcso
12 #01 pc 00004de8 /data/app-lib/comexamplehellojni-2/libhello-jniso
13 #02 pc 000056c8 /data/app-lib/comexamplehellojni-2/libhello-jniso
14 #03 pc 00004fb4 /data/app-lib/comexamplehellojni-2/libhello-jniso
15 #04 pc 00004f58 /data/app-lib/comexamplehellojni-2/libhello-jniso
16 #05 pc 000505b9 /system/lib/libdvmso
17 #06 pc 00068005 /system/lib/libdvmso
18 #07 pc 000278a0 /system/lib/libdvmso
19 #08 pc 0002b7fc /system/lib/libdvmso
20 #09 pc 00060fe1 /system/lib/libdvmso
21 #10 pc 0006100b /system/lib/libdvmso
22 #11 pc 0006c6eb /system/lib/libdvmso
23 #12 pc 00067a1f /system/lib/libdvmso
24 #13 pc 000278a0 /system/lib/libdvmso
25 #14 pc 0002b7fc /system/lib/libdvmso
26 #15 pc 00061307 /system/lib/libdvmso
27 #16 pc 0006912d /system/lib/libdvmso
28 #17 pc 000278a0 /system/lib/libdvmso
29 #18 pc 0002b7fc /system/lib/libdvmso
30 #19 pc 00060fe1 /system/lib/libdvmso
31 #20 pc 00049ff9 /system/lib/libdvmso
32 #21 pc 0004d419 /system/lib/libandroid_runtimeso
33 #22 pc 0004e1bd /system/lib/libandroid_runtimeso
34 #23 pc 00001d37 /system/bin/app_process
35 #24 pc 0001bd98 /system/lib/libcso
36 #25 pc 00001904 /system/bin/app_process
37
38 stack:
39 beb12340 012153f8
40 beb12344 00054290
41 beb12348 00000035
42 beb1234c beb123c0 [stack]
43
44……
如果你看过logcat打印的NDK错误时的日志就会知道,我省略了后面很多的内容,很多人看到这么多密密麻麻的日志就已经头晕脑胀了,即使是很多资深的Android开发者,在面对NDK日志时也大都默默的选择了无视。
“符号化”NDK错误信息的方法
其实,只要你细心的查看,再配合Google 提供的工具,完全可以快速的准确定位出错的代码位置,这个工作我们称之为“符号化”。需要注意的是,如果要对NDK错误进行符号化的工作,需要保留编译过程中产生的包含符号表的so文件,这些文件一般保存在$PROJECT_PATH/obj/local/目录下。
第一种方法:ndk-stack
这个命令行工具包含在NDK工具的安装目录,和ndk-build和其他一些常用的NDK命令放在一起,比如在我的电脑上,其位置是/android-ndk-r9d/ndk-stack。根据Google官方文档,NDK从r6版本开始提供ndk-stack命令,如果你用的之前的版本,建议还是尽快升级至最新的版本。使用ndk –stack命令也有两种方式
使用ndk-stack实时分析日志
在运行程序的同时,使用adb获取logcat日志,并通过管道符输出给ndk-stack,同时需要指定包含符号表的so文件位置;如果你的程序包含了多种CPU架构,在这里需求根据错误发生时的手机CPU类型,选择不同的CPU架构目录
第二种方法:使用addr2line和objdump命令
这个方法适用于那些,不满足于上述ndk-stack的简单用法,而喜欢刨根问底的程序员们,这两个方法可以揭示ndk-stack命令的工作原理是什么,尽管用起来稍微麻烦一点,但是可以满足一下程序员的好奇心。
先简单说一下这两个命令,在绝大部分的linux发行版本中都能找到他们,如果你的 *** 作系统是linux,而你测试手机使用的是Intel
x86系列,那么你使用系统中自带的命令就可以了。然而,如果仅仅是这样,那么绝大多数人要绝望了,因为恰恰大部分开发者使用的是Windows,而手机很有可能是armeabi系列。
别急,在NDK中自带了适用于各个 *** 作系统和CPU架构的工具链,其中就包含了这两个命令,只不过名字稍有变化,你可以在NDK目录的toolchains目录下找到他们。以我的Mac电脑为例,如果我要找的是适用于armeabi架构的工具,那么他们分别为arm-linux-androideabi-addr2line和arm-linux-androideabi-objdump;


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/10377790.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-08
下一篇 2023-05-08

发表评论

登录后才能评论

评论列表(0条)

保存