【踩坑记录】apk安装之后系统缓存目录下找不到so

1,146 阅读2分钟

问题背景

最近在研究快手的KOOM框架,自己在尝试本地实现的时候,遇到一个奇怪的问题。在KOOM中有一段利用xhook去hook data缓存目录下so的代码。

std::vector<const std::string> register_pattern = {"^/data/.*\.so$"};
std::vector<const std::string> ignore_pattern = {".*/libkoom-native.so$",
                                                 ".*/libxhook_lib.so$"};
                                                 
                                                 
if (ignore_list != nullptr) {
  for (std::string &item : *ignore_list) {
    ignore_pattern.push_back(".*/" + item + ".so$");
  }
}
if (selected_list != nullptr && !selected_list->empty()) {
  // only hook the so in selected list
  register_pattern.clear();
  for (std::string &item : *selected_list) {
    register_pattern.push_back("^/data/.*/" + item + ".so$");
  }
}
std::vector<std::pair<const std::string, void *const>> hook_entries = {
    std::make_pair("malloc", reinterpret_cast<void *>(WRAP(malloc))),
    std::make_pair("realloc", reinterpret_cast<void *>(WRAP(realloc))),
    std::make_pair("calloc", reinterpret_cast<void *>(WRAP(calloc))),
    std::make_pair("memalign", reinterpret_cast<void *>(WRAP(memalign))),
    std::make_pair("posix_memalign",
                   reinterpret_cast<void *>(WRAP(posix_memalign))),
    std::make_pair("free", reinterpret_cast<void *>(WRAP(free)))};

if (HookHelper::HookMethods(register_pattern, ignore_pattern, hook_entries)) {
  has_install_monitor_ = true;
  return true;
}

发现在安装了之后,同样xhook却不生效。区别在于自己写的demo的apk缓存目录下没有对应的so,而KOOM 的demo下面有。然后又去研究xhook的官方demo,发现xhook的demo在缓存目录下也是存在so的。

image.png

问题解决

反复对比自己的demo跟xhook的demo,最终发现问题是出在minSdk上,google在API21之后就不再解压apk中的so到lib目录下,所以当minsdk大于等于21的时候,缓存目录下就没有so。

image.png

引用一段GPT中给出的回答

在 Android 中,从运行时根据需要从 base.apk 文件中加载 .so 文件是从 Android 5.0(API 级别 21)开始引入的一个重要变化。

在 Android 4.4(API 级别 19)及更早的版本中,.so 文件必须位于应用程序的 lib 目录下,并在应用程序安装时一同被安装到设备上。这种方式称为静态加载,.so 文件在应用程序安装时就被解压到 lib 目录中,并在运行时直接从 lib 目录加载。

然而,从 Android 5.0(API 级别 21)开始,引入了一项名为 "APK 可执行文件的动态加载"(APK Executable Dynamic Loading)的特性。这个特性允许应用程序将 .so 文件打包到 base.apk 文件中,并在运行时根据需要从 base.apk 文件中加载 .so 文件。这种方式称为动态加载。

动态加载的好处是可以减小 APK 文件的大小,因为 .so 文件不再需要提前解压到 lib 目录中。而是在需要时从 base.apk 文件中加载,这样可以节省存储空间。此外,动态加载还提供了更灵活的方式,可以根据不同的设备架构加载适当的 .so 文件。

需要注意的是,动态加载需要开发者自行实现相应的逻辑,通常使用 System.loadLibrary() 方法或其他动态加载的技术来实现。这种方式在 Android 5.0 及更高版本中是推荐的做法,但在 Android 4.4 及更早的版本中仍然需要使用静态加载方式。