Android so文件

本篇简单介绍Android中so文件相关事项。html

CPU架构

目前主流的CPU架构:x86,ARM,MIPSjava

它们采用的指令集又分为CISC(复杂指令集)和RISC(精简指令集)两种android

CISC(复杂指令集)服务器

1.指令系统庞大,指令功能复杂,指令格式、寻址方式多网络

2.绝大多数指令需多个机器周期完成架构

3.各类指令均可访问存储器app

4.采用微程序控制ide

5.有专用寄存器,少许函数

6.难以用优化编译技术生成高效的目标代码程序性能

RISC(精简指令集):

1.统一指令编码,可快速解译;

2.泛用的暂存器,全部暂存器可用于全部内容,以及编译器设计的单纯化

3.单纯的寻址模式

4.硬件中支援少数资料型别

  • x86``CISC绝大部分pc都是x86架构。

  • ARM``RISC普遍应用在嵌入式系统

  • MIPS``RISC普遍被使用在许多电子产品、网络设备、我的娱乐装置与商业装置上

CPU架构和ABI

Android系统目前支持如下七种不一样的CPU架构:ARMv5ARMv7 (从2010年起),x86 (从2011年起),MIPS (从2012年起),ARMv8MIPS64x86_64 (从2014年起),每一种都关联着一个相应的应用程序二进制接口ABI(Application Binary Interface)。

ABI定义了二进制文件(尤为是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。

ABI\CPU armeabi armeabi-v7a arm64-v8a mips
ARMv5 支持
ARMv7 支持 支持
ARMv8 支持 支持 支持
MIPS 支持
MIPS64 支持
x86 支持 支持
x86_64 支持

ABI官方介绍

so文件

  • so机制让开发者最大化利用已有的C和C++代码,达到重用的效果,利用软件世界积累了几十年的优秀代码

  • so是二进制,没有解释编译的开消,用so实现的功能比纯java实现的功能要快

  • so内存分配不受Dalivik/ART的单个应用限制,减小OOM

  • 相对于java代码,二进制代码的反编译难度更大,一些核心代码能够考虑放在so中。

so文件的加载

so文件的加载,Android在System类中提供两种方法。

/**
  * See {@link Runtime#loadLibrary}.
  */
 public static void loadLibrary(String libName) {
     Runtime.getRuntime().loadLibrary(libName, VMStack.getCallingClassLoader());
 }
/**
  * See {@link Runtime#load}.
  */
 public static void load(String pathName) {
     Runtime.getRuntime().load(pathName, VMStack.getCallingClassLoader());
 }

System.loadLibrary

这是咱们最经常使用的一个方法,System.loadLibrary只须要传入so在Android.mk中定义的LOCAL_MODULE的值便可,系统会调用System.mapLibraryName把这个libName转化成对应平台的so的全称并去尝试寻找这个so加载。好比咱们的so文件全名为libmath.so,加载该动态库只须要传入math便可:

System.loadLibrary("math");

System.load

官方介绍:

Loads a code file with the specified filename from the local file system as a dynamic library.The filename argument must be a complete path name.

因此它为动态加载非apk打包期间内置的so文件提供了可能,也就是说可使用这个方法来指定咱们要加载的so文件的路径来动态的加载so文件。好比咱们在打包期间并不打包so文件,而是在应用运行时将当前设备适用的so文件从服务器上下载下来,放在/data/data/ /mydir下,而后在使用so时调用:

System.load("/data/data/<package-name>/mydir/libmath.so");

便可成功加载这个so,开始调用本地方法了。

其实loadLibrary和load最终都会调用nativeLoad(name, loader, ldLibraryPath)方法,只是由于loadLibrary的参数传入的仅仅是so的文件名,因此,loadLibrary须要首先找到这个文件的路径,而后加载这个so文件。
而load传入的参数是一个文件路径,因此它不须要去寻找这个文件路径,而是直接经过这个路径来加载so文件。

可是当咱们把须要加载的so文件放在SdCard中,会发生什么呢?把上面so的路径改为/mnt/sdcard/libmath.so,再尝试加载时,会获得以下错误:

java.lang.UnsatisfiedLinkError: dlopen failed: couldn't map "/mnt/sdcard/libmath.so" segment 1: Permission denied

这是由于SD卡等外部存储路径是一种可拆卸的(mounted)不可执行(noexec)的储存媒介,不能直接用来做为可执行文件的运行目录,使用前应该把可执行文件复制到APP内部存储下再运行。因此使用System.load加载so时要注意把so拷贝至/data/data/ /下。

so文件注意事项

1.不少设备都支持多于一种的ABI。但最好是针对特定平台提供相应平台的二进制包,从而获得更好的性能。

2.你应该尽量的提供专为每一个ABI优化过的.so文件,但要么所有支持,要么都不支持:你不该该混合着使用。你应该为每一个ABI目录提供对应的.so文件。
当一个应用安装在设备上,只有该设备支持的CPU架构对应的.so文件会被安装。在x86设备上,libs/x86目录中若是存在.so文件的话,会被安装,若是不存在,则会选择armeabi-v7a中的.so文件,若是也不存在,则选择armeabi目录中的.so文件(由于x86设备也支持armeabi-v7a和armeabi)。

3.使用NDK时,你可能会倾向于使用最新的编译平台,但事实上这是错误的,由于NDK平台不是后向兼容的,而是前向兼容的。推荐使用app的minSdkVersion对应的编译平台。

相关文章
相关标签/搜索