当前位置: 首页 > article >正文

安卓应用4字节不对齐导致so加载失败

今天把一个apk给厂商签名后直接push到机器的/system/app,结果运行app时显示so找不到。报错:

java stacktrace:
java.lang.UnsatisfiedLinkError: Library mmkv not found; tried [/system/lib/libmmkv.so, /product/lib/libmmkv.so]
at java.lang.Runtime.loadLibrary0(Runtime.java:1101)
at java.lang.System.loadLibrary(System.java:1669)
at com.tencent.mmkv.MMKV.doInitialize(MMKV.java:226)
at com.tencent.mmkv.MMKV.initialize(MMKV.java:208)
at com.tencent.mmkv.MMKV.initialize(MMKV.java:94)
at com.wesley.CustomApplication.onCreate(CustomApplication.kt:14)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1154)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5871)
at android.app.ActivityThread.access 1100 ( A c t i v i t y T h r e a d . j a v a : 199 ) a t a n d r o i d . a p p . A c t i v i t y T h r e a d 1100(ActivityThread.java:199) at android.app.ActivityThread 1100(ActivityThread.java:199)atandroid.app.ActivityThreadH.handleMessage(ActivityThread.java:1650)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922)

日志(xcrash 自己有so异常捕获,所以直到加载 mmkv 才抛出异常)

12-27 14:58:04.840 9717 9717 E System : ##loadLibrary0## /system/app/demo/demo_V1.0.0(2412261921)-release-signed.apk!/lib/armeabi-v7a/libxcrash.so error: dlopen failed: library “/system/app/demo/demo_V1.0.0(2412261921)-release-signed.apk!/lib/armeabi-v7a/libxcrash.so” not found, and try to find so file from the lib path
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: xcrash: NativeHandler System.loadLibrary failed
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: java.lang.UnsatisfiedLinkError: Library xcrash not found; tried [/system/lib/libxcrash.so, /product/lib/libxcrash.so]
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at java.lang.Runtime.loadLibrary0(Runtime.java:1101)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at java.lang.System.loadLibrary(System.java:1669)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at xcrash.NativeHandler.initialize(NativeHandler.java:89)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at xcrash.XCrash.init(XCrash.java:189)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at com.wesley.base.apm.XCrashWrapper.(XCrashWrapper.kt:131)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at com.wesley.base.apm.XCrashWrapper.(XCrashWrapper.kt:17)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at com.wesley.CastApplication.attachBaseContext(CastApplication.kt:43)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at android.app.Application.attach(Application.java:212)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at android.app.Instrumentation.newApplication(Instrumentation.java:1121)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at android.app.LoadedApk.makeApplication(LoadedApk.java:1065)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5842)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at android.app.ActivityThread.access 1100 ( A c t i v i t y T h r e a d . j a v a : 199 ) 12 − 2714 : 58 : 04.84397179717 E d e m o − X C r a s h W r a p p e r : a t a n d r o i d . a p p . A c t i v i t y T h r e a d 1100(ActivityThread.java:199) 12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at android.app.ActivityThread 1100(ActivityThread.java:199)122714:58:04.84397179717EdemoXCrashWrapper:atandroid.app.ActivityThreadH.handleMessage(ActivityThread.java:1650)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at android.os.Handler.dispatchMessage(Handler.java:106)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at android.os.Looper.loop(Looper.java:193)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at android.app.ActivityThread.main(ActivityThread.java:6669)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at java.lang.reflect.Method.invoke(Native Method)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
12-27 14:58:04.843 9717 9717 E demo-XCrashWrapper: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922)

因为安卓6开始支持直接加载apk内部so,如果编译后的 apk 内部 so 是不压缩的,那么就不需要释放到目录了。所以排除是因为不解压 so 到/system/app/demo/lib/arm 引起的问题,虽然这样也可以解决问题。

如果apk的minSdkVersion >= 23 并且 Android Gradle plugin >= 3.6.0情况下,打包时android:extractNativeLibs=false,apk的so默认是不压缩的。

在minSdkVersion < 23 或 Android Gradle plugin < 3.6.0情况下,打包时 android:extractNativeLibs=true,apk的so默认是压缩的。

然后,我尝试push没有给厂商签名前的版本 apk 到机器上是正常的,那么应该是厂商签名导致 apk 发生了变化。刚好前几天碰到安卓签名问题安卓15预置第三方apk时签名报错问题解决 - Wesley’s Blog。然后我就用命令看了一下:zipalign -c -v 4 demo_sign.apk

zipalign | Android Studio | Android Developers

显示:Verification FAILED,那就是 4 字节没有对齐。

查看签名版本apksigner verify -v demo_sign.apk | grep Verified

只有v1签名

~/Project$ apksigner verify -v demo_sign.apk | grep Verified

Verified using v1 scheme (JAR signing): true

Verified using v2 scheme (APK Signature Scheme v2): false

Verified using v3 scheme (APK Signature Scheme v3): false

Verified using v3.1 scheme (APK Signature Scheme v3.1): false

Verified using v4 scheme (APK Signature Scheme v4): false

Verified for SourceStamp: false

因为是v1签名,执行zipalign -v -p 4 demo_sign.apk demo_sign_align.apk对齐4 字节不会破坏厂商的签名信息,然后push进去果然好了。

然后我又试着安装没有对齐前的,结果直接报错了:

PS C:\Users\Wesley> adb install Y:\Project\demo_sign.apk

Performing Streamed Install

adb: failed to install Y:\Project\demo_sign.apk: Failure [INSTALL_FAILED_INVALID_APK: Failed to extract native libraries, res=-2]

但是系统扫描安装却是可以通过的,所以很难发现是字节不对齐引起的。

深究

之前直接搜索安卓java.lang.UnsatisfiedLinkError是很难找到针对这种问题的解决方法的。因为现在有了解决办法,所以换成UnsatisfiedLinkError zipalign进行谷歌搜索。结果就出来了:

android - java.lang.UnsatisfiedLinkError when installing as system app - Stack Overflow

zipflinger导致的UnsatisfiedLinkError分析 - 搜外SEO问答

zipflinger导致的UnsatisfiedLinkError分析_mb5ff2f24b42377的技术博客_51CTO博客

用 AI大模型总结一下:

这篇文章主要分析了在Android开发中,由于升级Android Gradle Plugin (AGP) 版本导致的UnsatisfiedLinkError问题,并提供了相应的解决方案。以下是文章的主要内容总结:

问题描述

  • 问题现象:在Android 9.0环境下,将AGP从3.6.1升级到4.1.0后,预装在/system/priv-app下的APP出现了UnsatisfiedLinkError崩溃。
  • 问题原因:升级AGP后,系统在加载so文件时失败,具体表现为so文件在APK中的对齐方式有问题。

问题分析

  • so文件加载流程:系统使用“!/”分隔符来定位so文件路径,并在APK中查找对应的entry。问题出在zipalign处理上,导致so文件的对齐不正确。
  • zipalign的作用:确保APK中所有未压缩数据在4字节边界上对齐,以便使用mmap()直接访问,减少RAM消耗。
  • 系统编译处理:Android系统在编译时会对privileged app执行uncompress-dexs操作,将压缩存储的dex文件变为不压缩存储。之后还会进行align-package操作。

问题原因

  • zipflinger工具:从AGP 4.1开始,默认在构建release版本时启用zipflinger工具进行打包。zipflinger改变了APK的打包方式,导致uncompress-dexs操作后zipalign出现问题。

解决方案

  • 禁用zipflinger:在app工程的gradle.properties中加入配置以禁用zipflinger。
  • 不解压 dex:DONT_UNCOMPRESS_PRIV_APPS_DEXS := true,可能会降低 dex 加载速度。
  • 使用zip2zip工具:在最新的AOSP源码中,使用zip2zip工具来处理dex文件的解压缩,以适配zipflinger打包的APK。
  • 其他方法:包括回退AGP版本、修改系统编译脚本等,但这些方法各有优缺点。

虽然引起问题的原因不一样,但都是因为字节不对齐引起的 so 找不到。

下面来分析一下具体原因:

so加载调用栈

ojluni/src/main/java/java/lang/System.java --> System.loadLibrary

ojluni/src/main/java/java/lang/Runtime.java --> Runtime.loadLibrary0 -> nativeLoad

ojluni/src/main/native/Runtime.c --> Runtime_nativeLoad

art/openjdkjvm/OpenjdkJvm.cc --> JVM_NativeLoad

art/runtime/java_vm_ext.cc --> JavaVMExt::LoadNativeLibrary

system/core/libnativeloader/native_loader.cpp --> OpenNativeLibrary

bionic/libdl/libdl.cpp --> android_dlopen_ext

bionic/linker/dlfcn.cpp --> __loader_android_dlopen_ext

bionic/linker/dlfcn.cpp --> dlopen_ext

bionic/linker/linker.cpp --> do_dlopen

bionic/linker/linker.cpp --> find_library

bionic/linker/linker.cpp --> find_libraries

bionic/linker/linker.cpp --> find_library_internal

bionic/linker/linker.cpp --> load_library

bionic/linker/linker.cpp --> open_library

bionic/linker/linker.cpp --> open_library_in_zipfile

重点看 bionic/linker/linker.cpp --> open_library_in_zipfile 这个函数,导致加载失败的是以下条件 entry.offset % PAGE_SIZE != 0

http://xrefandroid.com/android-9.0.0_r61/xref/bionic/linker/linker.cpp#992

if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
    close(fd);
    return -1;
}

总结来说,就是签名的时候破坏了4字节对齐,导致 so 加载失败。所以,以后碰到此类问题时,可以执行zipalign -c -v 4 xxx.apk先看一下是否4字节对齐。


http://www.kler.cn/a/468038.html

相关文章:

  • 鸿蒙NEXT使用request模块实现本地文件上传
  • 浅谈棋牌游戏开发流程七:反外挂与安全体系——守护游戏公平与玩家体验
  • node.js内置模块之---fs 模块
  • Spring SpEL表达式由浅入深
  • 基于Arduino的FPV头部追踪相机系统
  • 25年对AI产业的25点预测以及展望思考
  • javaEE-文件内容的读写
  • MySQL--》快速提高查询效率:SQL语句优化技巧与实践
  • 开源:软件世界的革命者
  • Windows远程--如何使用IP访问服务器
  • 桌面开发 的设计模式(Design Patterns)基础知识
  • 【Java回顾】Day4 异常机制
  • Ruby 数据类型
  • Unity 从零开始的框架搭建1-3 关于命令模式的一些思考
  • 四、VSCODE 使用GIT插件
  • 综合能源建模:理论、方法与实践
  • 行为模式3.迭代器模式
  • rsync命令常用同步方案
  • (leetcode算法题)528. 按权重随机选择
  • 记录一下core-js安装报错(core-js/modules/es.array.push.js core-js/modules/es.error.cause.js)
  • 简历_专业技能_熟悉Redis常用数据结构及其操作命令
  • 现代光学基础4
  • 如何下载 Chrome 历史版本 - 完整指南
  • SwiftUI 撸码常见错误 2 例漫谈
  • EPS32基础篇开发
  • vue 如何实现复制和粘贴操作