问题背景
最近在研究快手的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的。
问题解决
反复对比自己的demo跟xhook的demo,最终发现问题是出在minSdk上,google在API21之后就不再解压apk中的so到lib目录下,所以当minsdk大于等于21的时候,缓存目录下就没有so。
引用一段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 及更早的版本中仍然需要使用静态加载方式。