将 gradle 构建工具从 3.6.1 升级到 4.1.0 时,特权应用程序的 dlopen 失败

问题描述

我有一个位于 /system/priv-app/MyTestApp 中的应用程序。 android源代码环境为Android P(API 28)。

起初,MyTestApp.apk 是使用 gradle 构建工具 3.6.1 构建的。然后我将它升级到 4.1.0 并构建一个新的 MyTestApp.apk 并在 rom 中预构建它。所以崩溃发生了。

E AndroidRuntime: java.lang.UnsatisfiedLinkError: dlopen Failed: library "/system/priv-app/MyTestApp/MyTestApp.apk!/lib/armeabi-v7a/libmytest.so" not found
E AndroidRuntime:       at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
E AndroidRuntime:       at java.lang.System.loadLibrary(System.java:1669)

我拉取文件/system/priv-app/MyTestApp/MyTestApp.apk,解压后发现libmytest.so存在。这肯定是由 gradle 构建工具升级引起的。但我找不到原因。有人可以帮忙吗?

解决方法

查看源代码后,我发现在bionic/linker/linker.cpp

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

entry.offset % PAGE_SIZE != 0 此条件失败。

所以我猜 AGP 4.1+ 的 zipalign 有问题。

还在研究中。

,

只要未定义属性 DONT_UNCOMPRESS_PRIV_APPS_DEXS,Android 构建系统就会为特权应用解压嵌入在 apk 中的 dex 文件。解压定义如下

# Uncompress dex files embedded in an apk.
#
define uncompress-dexs
$(hide) if (zipinfo $@ '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then \
  tmpdir=$@.tmpdir; \
  rm -rf $$tmpdir && mkdir $$tmpdir; \
  unzip -q $@ '*.dex' -d $$tmpdir && \
  zip -qd $@ '*.dex' && \
  ( cd $$tmpdir && find . -type f | sort | zip -qD -X -0 ../$(notdir $@) -@ ) && \
  rm -rf $$tmpdir; \
  fi
endef

使用AGP 4.0构建apk时,解压dexs后,通过zipalign工具可以验证成功。

zipalign -v -c -p 4 MyTestApp.apk

但是当使用 AGP 4.1+(也包括 7.0-alpha)构建时,它无法通过 zipalign 工具进行验证。

但是我还没有找到原因。只是猜测 AGP 4.1+ 中的 apk 存档有一些新的变化。

,
android.useNewApkCreator=false

在 gradle.properties 中添加这一行可以解决这个问题。

但是从 AGP 3.6+ 开始,这个属性的默认值为 true。所以应该不是AGP 4.0和AGP 4.1的区别。

我很困惑。可能还有一些其他条件才能生效。

,

参考最新代码,uncompress-dexs 方法如下

https://android.googlesource.com/platform/build/+/master/core/definitions.mk#2385

# Uncompress dex files embedded in an apk.
#
define uncompress-dexs
  if (zipinfo $@ '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then \
    $(ZIP2ZIP) -i $@ -o $@.tmp -0 "classes*.dex" && \
    mv -f $@.tmp $@ ; \
  fi
endef