Android 应用开发中不可避免的会引入第三方的代码。如果是开源项目风险相对可控,如果引入商用的 SDK 那就要谨慎了,难免会有这样或那样的问题。比如我们今天要说的这一个。
对集成过第三方 SDK 的同学,上图中的目录结构应该不陌生。正常情况下我们只需要将不同版本的 so 文件分别放置。但如果我们要集成的这个第三方 SDK 偏偏没有 arm-v7a 的版本呢?是删除 armeabi-v7a 目录只保留 armeabi ?还是说两个目录下 .so 文件数不同也没有关系?系统会加载哪个 .so 呢?
如果只对结论感兴趣可以直接跳到最后
为了方便说明我们先引入 FAT Binary 的概念。我们知道不同的 CPU 支持的指令集也不一样,那么如果我们需要让 App 尽可能不同的 CPU 上都可以正常运行该怎么做呢?简单,只需要将不同版本的 Binary 放在一个文件里,运行时按需取用就可以了。这就是 FAT Binary 的典型实现。Android 实现 FAT 的方式有些不同,就是上边提到的将 .so 文件放置在相应文件夹中。在 Android 系统中 ndk 默认会生成如下 7 种 so。
在 apk 文件中带这么多版本的 .so 是一种很不经济的做法:
- mips / mips64: 极少用于手机可以忽略
- x86 / x86_64: x86 架构的手机都会包含由 Intel 提供的称为 Houdini 的指令集动态转码工具,实现 对 arm .so 的兼容,再考虑 x86 1% 以下的市场占有率,x86 相关的两个 .so 也是可以忽略的
- armeabi: ARM v5 这是相当老旧的一个版本,缺少对浮点数计算的硬件支持,在需要大量计算时有性能瓶颈
- armeabi-v7a: ARM v7 目前主流版本
- arm64-v8a: 64位支持
这样我们就可以明确 mips, mips64, x86, x86_64 这 4 个 .so 我们是不需要的。
我们回到开头提到的问题:
假定我们现在的情况是这样的(b.so 就是那个只有 armeabi 版本的第三方 so):
如果这样放置的话,在 ARM / ARM v7 两种设备上运行 apk 时会分别执行哪个 so 呢?
答案是:不确定……
这么坑爹的答案是怎么来的呢?
由于 Android 上 FAT binrary 的设计如此阳春,在 apk 安装时就需要根据 CPU 情况执行对应版本 so 的拷贝。对上边的情况最合理的一种做法应该是使用 armeabi-v7a/a.so 和 armeabi/b.so 这两个文件。Google 最初也是这么想的,然后就引入了 Bug…
Native library copy issue when install apk with different abi native libraries on device
上图是到 Android 4.4 还在使用的 so 文件拷贝逻辑,看起来没有问题?
坑爹是 Android 在安装 apk 文件时没有保证 zip entry 的扫描顺序,所以同样的文件放置会带来两种不同的安装结果:
看的有点头晕?简而言之,如果按我们上面的放置方式,安装后系统可能只拷贝了 armeabi-v7a/a.so。如果执行到 b.so 的逻辑,程序显然会 crash。
这边还有个小插曲,这个 bug 的发现者在提交时其实已经给出了完善的解决方案,但在经历了快有小一年的 code review 后 Android 官方表示:我们自己另起炉灶修好了=_=。
这个问题确实在 Android 5.0 已经 “修复” 了。“修复” 方式简单粗暴,不再以文件为粒度匹配 abi,直接拷贝整个文件夹=_=。所以如果按我们之前的放置方法,在 Android 5.0+ 如果执行到 b.so 也是一定会 crash 的。
上面提到,只保留 armeabi 文件夹从性能角度是不明智的。正确的做法是将 armeabi/b.so 复制一份到 armeabi-v7a/b.so. 这是由于 ARM v7 是前向兼容 ARM v5 的。
- 为了减小 apk 体积,只保留 armeabi 和 armeabi-v7a 两个文件夹,并保证这两个文件夹中 so 数量一致
- 对只提供 armeabi 版本的第三方 so,原样复制一份到 armeabi-v7a 文件夹
相关推荐
最近有个项目模块需要用到TCP Socket通讯,遇到了一个大坑,所以做了这个Demo。 本Demo主要实现了安卓(Android)TCP 客户端(Client)和服务器(Server)Demo的Socket通讯。以及对接硬件的项目数据在十六进制&&byte&&int...
【大坑传统美食首推土鸡城】是一个深受游客和美食爱好者欢迎的餐饮目的地,尤其在15年前,它已经成为台中大坑地区不可或缺的一部分。这个美食地标——“黑公羊土鸡城”,以其独特的土鸡料理和鲜美的地方特色菜肴而...
系统崩溃、蓝屏、程序运行异常等,这通常与操作系统、驱动程序或应用程序有关。学会安全模式启动、系统还原、重装系统等技巧,能帮助我们排查问题。同时,保持软件及时更新,安装杀毒软件防止病毒、恶意软件侵入,也...
该网站由一个团队在杨子青老师的指导下开发完成,旨在整合大坑景点与周边商家信息,打造一个集电子地图、个性化旅游体验于一体的网络服务。 一、开发动机与目的 开发动机主要源于电子地图和旅游资讯的需求。专题...
然而,企业在转型过程中可能会遇到诸多挑战,以下12个大坑是企业在数字化转型时需要特别警惕的: 1. **不了解转型本质和目的**:企业必须清楚地认识到,数字化转型不仅仅是技术升级,更关乎企业整体战略的调整。...
3. **工作线程占用问题**:在一个服务中,若某接口因公网调用而发生超时,则该接口所占用的工作线程将在一段时间内无法释放,进而影响到其他正常运行的接口。 #### 二、优化方案 针对上述问题,本文提出了以下几种...
GDAL 库是一个开源的地理信息系统(GIS)库,提供了对栅格和矢量数据的支持。在 Java 中使用 GDAL 库需要将其配置到 Java 项目中,但是在配置过程中容易遇到版本不一致的问题。 GDAL 版本不一致的原因 GDAL 库有多...
“大坑湖”的变迁和华联商城的重组,虽然发生在不同的领域,但它们共同勾勒出中国经济发展的一个重要方面——市场化改革和创新策略在解决历史遗留问题、推动经济和社会持续繁荣中的关键作用。在这两个案例中,我们既...
这里有一个大坑,我的viewGroup中有一个这个属性android:descendantFocusability=”blocksDescendants” 开始没有注意到,试了好多方法都不行,后来才看到这个属性,顺便科普一下,这个属性有三个值~ ...
在QT编程中,创建带有界面的静态库是一个常见的需求,特别是在开发跨平台的应用程序时。然而,这个过程中可能会遇到一些陷阱,特别是在尝试显示界面时。本文将深入探讨标题和描述中提到的问题:“QT制作带有界面的...
本文将详细探讨五个企业在处理差旅费时常见的税务大坑,并提出相应的解决建议,以帮助企业避免这些陷阱。 首先,企业需要注意的是差旅费核算范围的准确性。差旅费一般包括交通、住宿、餐饮等基本费用,但在实际操作...
在实际使用过程中,可能会遇到的一个陷阱是,如果 JWT 生成和验证过程中的编码不一致,会导致认证失败。例如,如果你的 JWT 生成库使用了标准的 Base64 编码,但验证时使用了 Base64Url 解码,或者反之,将会导致...
在ES6的类语法中,处理`state`和`props`的方式与ES5有所不同,这可能会导致开发者遇到一些陷阱。让我们深入探讨一下这些变化以及如何正确地设置和使用`state`和`props`。 首先,`state`代表组件内部可变的状态,它...
在描述中提到了一个博客链接,虽然没有具体内容,但通常博主会分享在实际操作中遇到的问题和解决方案。 JBOSS 4.0.5 GA是JBOSS应用服务器的一个早期版本,它是一个基于Java的开源应用服务器,广泛用于部署和管理...
综上所述,在运营数据分析和挖掘过程中,聚类分析是一个不可或缺的工具。为了确保聚类分析的准确性和有效性,我们需要特别关注数据异常的影响、选择恰当的聚类算法以及有效处理大规模数据的策略。在实际应用中,根据...
记一次 Data Binding 在 library module 中遇到的大坑 使用 Data Binding 也有半年多了,从最初的 setVariable,替换 findViewById,到比较高级的双向绑定,自定义 Adapter、Component,查看源码了解编译、运行流程...
DownloadManager之坑前言代码调试第一次调试第二次调试解决方案第一步第二步第三步 前言 最近在学网络编程, 学到DownloadManager时, 觉得也就几个方法, 那就整一下呗!心里想着也应该花不了多久。我就打算到网络...
- **成为领域专家**:文中举例通过深入研究一个特定领域的细节(如门头设计),并在该领域内积累足够的知识和经验,最终可以成为该领域的专家。 ### 5. 社区反馈 - **共鸣与反思**:社区成员对文中提到的观点表示...
- 安全第一:在设计方案中,首要考虑的是施工过程中的人员安全,确保所有操作符合国家安全法规,避免事故的发生。 - 质量优先:工程质量是水库工程的生命线,设计必须遵循严格的质量标准和规范,确保工程长期稳定...