-
-
[原创]andorid linker 解读1----从loadLibrary到dlopen
-
发表于: 2020-12-31 13:21 10737
-
Android 版本:android-8.0.0_r4
System.loadLibrary源码位于:./libcore/ojluni/src/main/java/java/lang/System.java
可以看到然后又调用了Runtime.java的loadLibrary0方法:./libcore/ojluni/src/main/java/java/lang/Runtime.java
这个方法主要有两个作用:
首先会判断loader 不为空来执行上面两步,如果为空,则换个方法继续执行上面两步。
拿到库的搜索路径,调用了native 的nativeLoad方法。
native函数在libcore/ojluni/src/main/native/register.cpp,统一注册,
其中我们需要的nativeLoad函数在libcore/ojluni/src/main/native/Runtime.c 文件下
继续跟:
继续跟android::OpenNativeLibrary , system/core/libnativeloader/native_loader.cpp
有两个点,class_loader == NULL , 和非空的情况。 。不晓得这两种是什么情况。。。。大神可以指教下。第一个过程直接走dlopen。第二个过程,走android_dlopen_ext , 两个函数最终都会走到do_dlopen 来打开so 。
find_library内部调用重载函数find_library ,内部的重载函数就是本次分析的重点。
关键函数到位了
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), libname);
}
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), libname);
}
synchronized void loadLibrary0(ClassLoader loader, String libname) {
if
(libname.indexOf((
int
)
File
.separatorChar) !
=
-
1
) {
throw new UnsatisfiedLinkError(
"Directory separator should not appear in library name: "
+
libname);
}
String libraryName
=
libname;
if
(loader !
=
null) {
String filename
=
loader.findLibrary(libraryName);
if
(filename
=
=
null) {
throw new UnsatisfiedLinkError(loader
+
" couldn't find \""
+
System.mapLibraryName(libraryName)
+
"\""
);
}
String error
=
doLoad(filename, loader);
if
(error !
=
null) {
throw new UnsatisfiedLinkError(error);
}
return
;
}
String filename
=
System.mapLibraryName(libraryName);
List
<String> candidates
=
new ArrayList<String>();
String lastError
=
null;
for
(String directory : getLibPaths()) {
String candidate
=
directory
+
filename;
candidates.add(candidate);
if
(IoUtils.canOpenReadOnly(candidate)) {
String error
=
doLoad(candidate, loader);
if
(error
=
=
null) {
return
;
/
/
We successfully loaded the library. Job done.
}
lastError
=
error;
}
}
if
(lastError !
=
null) {
throw new UnsatisfiedLinkError(lastError);
}
throw new UnsatisfiedLinkError(
"Library "
+
libraryName
+
" not found; tried "
+
candidates);
}
synchronized void loadLibrary0(ClassLoader loader, String libname) {
if
(libname.indexOf((
int
)
File
.separatorChar) !
=
-
1
) {
throw new UnsatisfiedLinkError(
"Directory separator should not appear in library name: "
+
libname);
}
String libraryName
=
libname;
if
(loader !
=
null) {
String filename
=
loader.findLibrary(libraryName);
if
(filename
=
=
null) {
throw new UnsatisfiedLinkError(loader
+
" couldn't find \""
+
System.mapLibraryName(libraryName)
+
"\""
);
}
String error
=
doLoad(filename, loader);
if
(error !
=
null) {
throw new UnsatisfiedLinkError(error);
}
return
;
}
String filename
=
System.mapLibraryName(libraryName);
List
<String> candidates
=
new ArrayList<String>();
String lastError
=
null;
for
(String directory : getLibPaths()) {
String candidate
=
directory
+
filename;
candidates.add(candidate);
if
(IoUtils.canOpenReadOnly(candidate)) {
String error
=
doLoad(candidate, loader);
if
(error
=
=
null) {
return
;
/
/
We successfully loaded the library. Job done.
}
lastError
=
error;
}
}
if
(lastError !
=
null) {
throw new UnsatisfiedLinkError(lastError);
}
throw new UnsatisfiedLinkError(
"Library "
+
libraryName
+
" not found; tried "
+
candidates);
}
private String doLoad(String name, ClassLoader loader) {
String librarySearchPath
=
null;
if
(loader !
=
null && loader instanceof BaseDexClassLoader) {
BaseDexClassLoader dexClassLoader
=
(BaseDexClassLoader) loader;
librarySearchPath
=
dexClassLoader.getLdLibraryPath();
}
synchronized (this) {
return
nativeLoad(name, loader, librarySearchPath);
}
}
private String doLoad(String name, ClassLoader loader) {
String librarySearchPath
=
null;
if
(loader !
=
null && loader instanceof BaseDexClassLoader) {
BaseDexClassLoader dexClassLoader
=
(BaseDexClassLoader) loader;
librarySearchPath
=
dexClassLoader.getLdLibraryPath();
}
synchronized (this) {
return
nativeLoad(name, loader, librarySearchPath);
}
}
private static native String nativeLoad(String filename, ClassLoader loader,String ibrarySearchPath);
private static native String nativeLoad(String filename, ClassLoader loader,String ibrarySearchPath);
JNIEXPORT jstring JVM_NativeLoad(JNIEnv
*
env,
jstring javaFilename,
jobject javaLoader,
jstring javaLibrarySearchPath) {
ScopedUtfChars filename(env, javaFilename);
if
(filename.c_str()
=
=
NULL) {
return
NULL;
}
std::string error_msg;
{
art::JavaVMExt
*
vm
=
art::Runtime::Current()
-
>GetJavaVM();
bool
success
=
vm
-
>LoadNativeLibrary(env,
filename.c_str(),
javaLoader,
javaLibrarySearchPath,
&error_msg);
if
(success) {
return
nullptr;
}
}
/
/
Don't let a pending exception
from
JNI_OnLoad cause a CheckJNI issue with NewStringUTF.
env
-
>ExceptionClear();
return
env
-
>NewStringUTF(error_msg.c_str());
}
JNIEXPORT jstring JVM_NativeLoad(JNIEnv
*
env,
jstring javaFilename,
jobject javaLoader,
jstring javaLibrarySearchPath) {
ScopedUtfChars filename(env, javaFilename);
if
(filename.c_str()
=
=
NULL) {
return
NULL;
}
std::string error_msg;
{
art::JavaVMExt
*
vm
=
art::Runtime::Current()
-
>GetJavaVM();
bool
success
=
vm
-
>LoadNativeLibrary(env,
filename.c_str(),
javaLoader,
javaLibrarySearchPath,
&error_msg);
if
(success) {
return
nullptr;
}
}
/
/
Don't let a pending exception
from
JNI_OnLoad cause a CheckJNI issue with NewStringUTF.
env
-
>ExceptionClear();
return
env
-
>NewStringUTF(error_msg.c_str());
}
bool
JavaVMExt::LoadNativeLibrary(JNIEnv
*
env,
const std::string& path,
jobject class_loader,
jstring library_path,
std::string
*
error_msg) {
error_msg
-
>clear();
/
/
See
if
we've already loaded this library. If we have,
and
the
class
loader matches,
return
successfully without doing anything.
。。。。。 , 已经加载了so
if
(library !
=
nullptr) {
if
(library
-
>GetClassLoaderAllocator() !
=
class_loader_allocator) {
StringAppendF(error_msg,
"Shared library \"%s\" already opened by "
"ClassLoader %p; can't open in ClassLoader %p"
,
path.c_str(), library
-
>GetClassLoader(), class_loader);
LOG(WARNING) << error_msg;
return
false;
}
VLOG(jni) <<
"[Shared library \""
<< path <<
"\" already loaded in "
<<
" ClassLoader "
<< class_loader <<
"]"
;
if
(!library
-
>CheckOnLoadResult()) {
StringAppendF(error_msg,
"JNI_OnLoad failed on a previous attempt "
"to load \"%s\""
, path.c_str());
return
false;
}
return
true;
}
.........
/
/
没有加载过so , 就调用OpenNativeLibrary来加载so。
Locks::mutator_lock_
-
>AssertNotHeld(
self
);
const char
*
path_str
=
path.empty() ? nullptr : path.c_str();
bool
needs_native_bridge
=
false;
void
*
handle
=
android::OpenNativeLibrary(env,
runtime_
-
>GetTargetSdkVersion(),
path_str,
class_loader,
library_path,
&needs_native_bridge,
error_msg);
VLOG(jni) <<
"[Call to dlopen(\""
<< path <<
"\", RTLD_NOW) returned "
<< handle <<
"]"
;
if
(handle
=
=
nullptr) {
VLOG(jni) <<
"dlopen(\""
<< path <<
"\", RTLD_NOW) failed: "
<<
*
error_msg;
return
false;
}
.........
/
/
要是so加载成功后,还要看有没有JNI_OnLoad函数,来判断native函数是静态注册还是Jni动态注册。
bool
was_successful
=
false;
void
*
sym
=
library
-
>FindSymbol(
"JNI_OnLoad"
, nullptr);
if
(sym
=
=
nullptr) {
VLOG(jni) <<
"[No JNI_OnLoad found in \""
<< path <<
"\"]"
;
was_successful
=
true;
}
else
{
/
/
Call JNI_OnLoad. We have to override the current
class
/
/
loader, which will always be
"null"
since the stuff at the
/
/
top of the stack
is
around Runtime.loadLibrary(). (See
/
/
the comments
in
the JNI FindClass function.)
ScopedLocalRef<jobject> old_class_loader(env, env
-
>NewLocalRef(
self
-
>GetClassLoaderOverride()));
self
-
>SetClassLoaderOverride(class_loader);
VLOG(jni) <<
"[Calling JNI_OnLoad in \""
<< path <<
"\"]"
;
typedef
int
(
*
JNI_OnLoadFn)(JavaVM
*
, void
*
);
JNI_OnLoadFn jni_on_load
=
reinterpret_cast<JNI_OnLoadFn>(sym);
int
version
=
(
*
jni_on_load)(this, nullptr);
.......
}
bool
JavaVMExt::LoadNativeLibrary(JNIEnv
*
env,
const std::string& path,
jobject class_loader,
jstring library_path,
std::string
*
error_msg) {
error_msg
-
>clear();
/
/
See
if
we've already loaded this library. If we have,
and
the
class
loader matches,
return
successfully without doing anything.
。。。。。 , 已经加载了so
if
(library !
=
nullptr) {
if
(library
-
>GetClassLoaderAllocator() !
=
class_loader_allocator) {
StringAppendF(error_msg,
"Shared library \"%s\" already opened by "
"ClassLoader %p; can't open in ClassLoader %p"
,
path.c_str(), library
-
>GetClassLoader(), class_loader);
LOG(WARNING) << error_msg;
return
false;
}
VLOG(jni) <<
"[Shared library \""
<< path <<
"\" already loaded in "
<<
" ClassLoader "
<< class_loader <<
"]"
;
if
(!library
-
>CheckOnLoadResult()) {
StringAppendF(error_msg,
"JNI_OnLoad failed on a previous attempt "
"to load \"%s\""
, path.c_str());
return
false;
}
return
true;
}
.........
/
/
没有加载过so , 就调用OpenNativeLibrary来加载so。
Locks::mutator_lock_
-
>AssertNotHeld(
self
);
const char
*
path_str
=
path.empty() ? nullptr : path.c_str();
bool
needs_native_bridge
=
false;
void
*
handle
=
android::OpenNativeLibrary(env,
runtime_
-
>GetTargetSdkVersion(),
path_str,
class_loader,
library_path,
&needs_native_bridge,
error_msg);
VLOG(jni) <<
"[Call to dlopen(\""
<< path <<
"\", RTLD_NOW) returned "
<< handle <<
"]"
;
if
(handle
=
=
nullptr) {
VLOG(jni) <<
"dlopen(\""
<< path <<
"\", RTLD_NOW) failed: "
<<
*
error_msg;
return
false;
}
.........
/
/
要是so加载成功后,还要看有没有JNI_OnLoad函数,来判断native函数是静态注册还是Jni动态注册。
bool
was_successful
=
false;
void
*
sym
=
library
-
>FindSymbol(
"JNI_OnLoad"
, nullptr);
if
(sym
=
=
nullptr) {
VLOG(jni) <<
"[No JNI_OnLoad found in \""
<< path <<
"\"]"
;
was_successful
=
true;
}
else
{
/
/
Call JNI_OnLoad. We have to override the current
class
/
/
loader, which will always be
"null"
since the stuff at the
/
/
top of the stack
is
around Runtime.loadLibrary(). (See
/
/
the comments
in
the JNI FindClass function.)
ScopedLocalRef<jobject> old_class_loader(env, env
-
>NewLocalRef(
self
-
>GetClassLoaderOverride()));
self
-
>SetClassLoaderOverride(class_loader);
VLOG(jni) <<
"[Calling JNI_OnLoad in \""
<< path <<
"\"]"
;
typedef
int
(
*
JNI_OnLoadFn)(JavaVM
*
, void
*
);
JNI_OnLoadFn jni_on_load
=
reinterpret_cast<JNI_OnLoadFn>(sym);
int
version
=
(
*
jni_on_load)(this, nullptr);
.......
}
void
*
OpenNativeLibrary(JNIEnv
*
env,
int32_t target_sdk_version,
const char
*
path,
jobject class_loader,
jstring library_path,
bool
*
needs_native_bridge,
std::string
*
error_msg) {
#if defined(__ANDROID__)
UNUSED(target_sdk_version);
if
(class_loader
=
=
nullptr) {
*
needs_native_bridge
=
false;
return
dlopen(path, RTLD_NOW);
}
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
NativeLoaderNamespace ns;
if
(!g_namespaces
-
>FindNamespaceByClassLoader(env, class_loader, &ns)) {
if
(!g_namespaces
-
>Create(env,
target_sdk_version,
class_loader,
false
/
*
is_shared
*
/
,
false
/
*
is_for_vendor
*
/
,
library_path,
nullptr,
&ns,
error_msg)) {
return
nullptr;
}
}
if
(ns.is_android_namespace()) {
android_dlextinfo extinfo;
extinfo.flags
=
ANDROID_DLEXT_USE_NAMESPACE;
extinfo.library_namespace
=
ns.get_android_ns();
void
*
handle
=
android_dlopen_ext(path, RTLD_NOW, &extinfo);
if
(handle
=
=
nullptr) {
*
error_msg
=
dlerror();
}
*
needs_native_bridge
=
false;
return
handle;
}
else
{
void
*
handle
=
NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
if
(handle
=
=
nullptr) {
*
error_msg
=
NativeBridgeGetError();
}
*
needs_native_bridge
=
true;
return
handle;
}
#else
UNUSED(env, target_sdk_version, class_loader, library_path);
*
needs_native_bridge
=
false;
void
*
handle
=
dlopen(path, RTLD_NOW);
if
(handle
=
=
nullptr) {
if
(NativeBridgeIsSupported(path)) {
*
needs_native_bridge
=
true;
handle
=
NativeBridgeLoadLibrary(path, RTLD_NOW);
if
(handle
=
=
nullptr) {
*
error_msg
=
NativeBridgeGetError();
}
}
else
{
*
needs_native_bridge
=
false;
*
error_msg
=
dlerror();
}
}
return
handle;
#endif
}
void
*
OpenNativeLibrary(JNIEnv
*
env,
int32_t target_sdk_version,
const char
*
path,
jobject class_loader,
jstring library_path,
bool
*
needs_native_bridge,
std::string
*
error_msg) {
#if defined(__ANDROID__)
UNUSED(target_sdk_version);
if
(class_loader
=
=
nullptr) {
*
needs_native_bridge
=
false;
return
dlopen(path, RTLD_NOW);
}
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
NativeLoaderNamespace ns;
if
(!g_namespaces
-
>FindNamespaceByClassLoader(env, class_loader, &ns)) {
if
(!g_namespaces
-
>Create(env,
target_sdk_version,
class_loader,
false
/
*
is_shared
*
/
,
false
/
*
is_for_vendor
*
/
,
library_path,
nullptr,
&ns,
error_msg)) {
return
nullptr;
}
}
if
(ns.is_android_namespace()) {
android_dlextinfo extinfo;
extinfo.flags
=
ANDROID_DLEXT_USE_NAMESPACE;
extinfo.library_namespace
=
ns.get_android_ns();
void
*
handle
=
android_dlopen_ext(path, RTLD_NOW, &extinfo);
if
(handle
=
=
nullptr) {
*
error_msg
=
dlerror();
}
*
needs_native_bridge
=
false;
return
handle;
}
else
{
void
*
handle
=
NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
if
(handle
=
=
nullptr) {
*
error_msg
=
NativeBridgeGetError();
}
*
needs_native_bridge
=
true;
return
handle;
}
#else
UNUSED(env, target_sdk_version, class_loader, library_path);
*
needs_native_bridge
=
false;
void
*
handle
=
dlopen(path, RTLD_NOW);
if
(handle
=
=
nullptr) {
if
(NativeBridgeIsSupported(path)) {
*
needs_native_bridge
=
true;
handle
=
NativeBridgeLoadLibrary(path, RTLD_NOW);
if
(handle
=
=
nullptr) {
*
error_msg
=
NativeBridgeGetError();
}
}
else
{
*
needs_native_bridge
=
false;
*
error_msg
=
dlerror();
}
}
return
handle;
#endif
}
void
*
do_dlopen(const char
*
name,
int
flags,
const android_dlextinfo
*
extinfo,
const void
*
caller_addr) {
/
/
在此之前都是针对,flag 和extinfo flag的处理。
const char
*
translated_name
=
name;
if
(g_is_asan && translated_name !
=
nullptr && translated_name[
0
]
=
=
'/'
) {
char original_path[PATH_MAX];
if
(realpath(name, original_path) !
=
nullptr) {
asan_name_holder
=
std::string(kAsanLibDirPrefix)
+
original_path;
LD_LOG(kLogDlopen,
"... pareto's here realpath =\"%s\""
,name);
if
(file_exists(asan_name_holder.c_str())) {
soinfo
*
si
=
nullptr;
if
(find_loaded_library_by_realpath(ns, original_path, true, &si)) {
PRINT
(
"linker_asan dlopen NOT translating \"%s\" -> \"%s\": library already loaded"
, name,
asan_name_holder.c_str());
}
else
{
PRINT
(
"linker_asan dlopen translating \"%s\" -> \"%s\""
, name, translated_name);
translated_name
=
asan_name_holder.c_str();
}
}
}
}
ProtectedDataGuard guard;
/
/
关注点 find_library
soinfo
*
si
=
find_library(ns, translated_name, flags, extinfo, caller);
loading_trace.End();
if
(si !
=
nullptr) {
void
*
handle
=
si
-
>to_handle();
/
/
调用init
si
-
>call_constructors();
return
handle;
}
return
nullptr;
}
void
*
do_dlopen(const char
*
name,
int
flags,
const android_dlextinfo
*
extinfo,
const void
*
caller_addr) {
/
/
在此之前都是针对,flag 和extinfo flag的处理。
const char
*
translated_name
=
name;
if
(g_is_asan && translated_name !
=
nullptr && translated_name[
0
]
=
=
'/'
) {
char original_path[PATH_MAX];
if
(realpath(name, original_path) !
=
nullptr) {
asan_name_holder
=
std::string(kAsanLibDirPrefix)
+
original_path;
LD_LOG(kLogDlopen,
"... pareto's here realpath =\"%s\""
,name);
if
(file_exists(asan_name_holder.c_str())) {
soinfo
*
si
=
nullptr;
if
(find_loaded_library_by_realpath(ns, original_path, true, &si)) {
PRINT
(
"linker_asan dlopen NOT translating \"%s\" -> \"%s\": library already loaded"
, name,
asan_name_holder.c_str());
}
else
{
PRINT
(
"linker_asan dlopen translating \"%s\" -> \"%s\""
, name, translated_name);
translated_name
=
asan_name_holder.c_str();
}
}
}
}
ProtectedDataGuard guard;
/
/
关注点 find_library
soinfo
*
si
=
find_library(ns, translated_name, flags, extinfo, caller);
loading_trace.End();
if
(si !
=
nullptr) {
void
*
handle
=
si
-
>to_handle();
/
/
调用init
si
-
>call_constructors();
return
handle;
}
return
nullptr;
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2020-12-31 16:48
被pareto编辑
,原因: 修改标题
赞赏
他的文章
- [分享]local Key Attestation 验证饶过 9063
- [原创]Key Attestation 密钥认证流程和饶过思路 17515
- [原创]模拟点击品类分析 10288
- [原创]android 在未加载模块的某偏移地址处下断点的小插件 15797
- null 10799
看原图
赞赏
雪币:
留言: