安卓JVM加载so库流程
好久没有写点东西发了,工作中的事情有点杂,也找不到整块东西可以写的。
最近调查了一个问题,稍微追了一下流程,这里记录一下。
1. 问题背景
由于我们支持的设备相对比竞品,zygote进程多占用了好几倍的内存空间。通过dump meminfo后发现,我们的设备在so库,ttf,和unkonwn mmap的内存空间相比竞品一共大了20多M,其中so库多了15M左右。
通过查看zygote进程的smaps,确定了占用空间最大的几个so库确实是我们自己的。虽然确定了内存占用大的原因,还是得把这些so库是加载在zygote进程中的时机确定了才行。
我的第一反应就是在zygote启动时,加载sharedLibrary()时,把这些库加载了,于是去看了这部分源码,并没有。
通过反复调试以及追踪源码,最后发现是在JVM启动的过程中加载了这些so库,这些so库的配置在“system/etc/public.libraries.txt”下。
这个文件里配置的都是public的so库,能够被普通app访问的。类似的配置文件还有“vendor/etc/”下面的,还有一些其他的配置地方,我没有深入去看,想要看的盆友可以自己去看源码或者注释。
下面我就带大家一起看看虚拟机加载这些so库的流程。
2. JVM加载so库流程
调用栈:
frameworks/base/cmds/app_process/app_main.cpp
? ---->runtime.start(“com.android.internal.os.ZygoteInit”, args, zygote);
frameworks/base/core/jni/AndroidRuntime.cpp
? ---->AndroidRuntime::startVm
? —>JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs)
art/runtime/jni/java_vm_ext.cc
? —>android::InitializeNativeLoader();
system/core/libnativeloader/native_loader.cpp
? ---->Initialize()
? ---->ReadConfig(public_native_libraries_system_config, &sonames, always_true, &error_msg)
其中,public_native_libraries_system_config 为 system/etc/public.libraries.txt
这部分流程是在安卓设备开机过程中的,在执行ZygoteInit.main()之前会先启动java虚拟机的,这样fork其他java进程的时候,java环境就已经有了,不用再创建虚拟机了。
最后贴一下Initialize()函数:
void Initialize() {
if (initialized_) {
return;
}
std::vector<std::string> sonames;
const char* android_root_env = getenv("ANDROID_ROOT");
std::string root_dir = android_root_env != nullptr ? android_root_env : "/system";
std::string public_native_libraries_system_config =
root_dir + kPublicNativeLibrariesSystemConfigPathFromRoot;
std::string llndk_native_libraries_system_config =
root_dir + kLlndkNativeLibrariesSystemConfigPathFromRoot;
std::string vndksp_native_libraries_system_config =
root_dir + kVndkspNativeLibrariesSystemConfigPathFromRoot;
std::string product_public_native_libraries_dir = "/product/etc";
std::string error_msg;
LOG_ALWAYS_FATAL_IF(
!ReadConfig(public_native_libraries_system_config, &sonames, always_true, &error_msg),
"Error reading public native library list from \"%s\": %s",
public_native_libraries_system_config.c_str(), error_msg.c_str());
if (is_debuggable()) {
const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
if (additional_libs != nullptr && additional_libs[0] != '\0') {
std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
std::copy(additional_libs_vector.begin(), additional_libs_vector.end(),
std::back_inserter(sonames));
}
}
removePublicLibsIfExistsInRuntimeApex(sonames);
for (const auto& soname : sonames) {
LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
"Error preloading public library %s: %s", soname.c_str(), dlerror());
}
system_public_libraries_ = base::Join(sonames, ':');
sonames.clear();
ReadExtensionLibraries(base::Dirname(public_native_libraries_system_config).c_str(), &sonames);
oem_public_libraries_ = base::Join(sonames, ':');
sonames.clear();
ReadExtensionLibraries(product_public_native_libraries_dir.c_str(), &sonames);
product_public_libraries_ = base::Join(sonames, ':');
insert_vndk_version_str(&llndk_native_libraries_system_config);
insert_vndk_version_str(&vndksp_native_libraries_system_config);
sonames.clear();
ReadConfig(llndk_native_libraries_system_config, &sonames, always_true);
system_llndk_libraries_ = base::Join(sonames, ':');
sonames.clear();
ReadConfig(vndksp_native_libraries_system_config, &sonames, always_true);
system_vndksp_libraries_ = base::Join(sonames, ':');
sonames.clear();
ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames, always_true, nullptr);
vendor_public_libraries_ = base::Join(sonames, ':');
}
|