在Android中,有个加载so的逻辑,System.LoadLibrary(“so文件名”); Android版本为9.0.0,代码来自下面的网址 androidxref.com/9.0.0_r3/ 我们直接定位如下方法 因为是静态方法,所以可以直接调用
1667 @CallerSensitive
1668 public static void loadLibrary(String libname) {
1669 Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), libname);
1670 }
我们看下这个loadLibrary0方法,方法有两个参数。
991 public void loadLibrary(String libname, ClassLoader classLoader) {
992 checkTargetSdkVersionForLoad("java.lang.Runtime#loadLibrary(String, ClassLoader)");
993 java.lang.System.logE("java.lang.Runtime#loadLibrary(String, ClassLoader)" +
994 " is private and will be removed in a future Android release");
995 loadLibrary0(classLoader, libname);
996 }
997
998 synchronized void loadLibrary0(ClassLoader loader, String libname) {
999 if (libname.indexOf((int)File.separatorChar) != -1) {
1000 throw new UnsatisfiedLinkError(
1001 "Directory separator should not appear in library name: " + libname);
1002 }
1003 String libraryName = libname;
1004 if (loader != null) {
1005 String filename = loader.findLibrary(libraryName);
1006 if (filename == null) {
1007
1008
1009
1010
1011 throw new UnsatisfiedLinkError(loader + " couldn't find \"" +
1012 System.mapLibraryName(libraryName) + "\"");
1013 }
1014 String error = nativeLoad(filename, loader);
1015 if (error != null) {
1016 throw new UnsatisfiedLinkError(error);
1017 }
1018 return;
1019 }
1020
1021 String filename = System.mapLibraryName(libraryName);
1022 List<String> candidates = new ArrayList<String>();
1023 String lastError = null;
1024 for (String directory : getLibPaths()) {
1025 String candidate = directory + filename;
1026 candidates.add(candidate);
1027
1028 if (IoUtils.canOpenReadOnly(candidate)) {
1029 String error = nativeLoad(candidate, loader);
1030 if (error == null) {
1031 return;
1032 }
1033 lastError = error;
1034 }
1035 }
1036
1037 if (lastError != null) {
1038 throw new UnsatisfiedLinkError(lastError);
1039 }
1040 throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
1041 }
如下代码获取文件名字,
1005 String filename = loader.findLibrary(libraryName);
文件名字不为空调用如下代码
1014 String error = nativeLoad(filename, loader);
如果error不为空直接抛出异常。不为空直接返回
1015 if (error != null) {
1016 throw new UnsatisfiedLinkError(error);
1017 }
1018 return;
下面的代码是没有ClassLoader 的情况下执行的。 相关逻辑基本差不多。 获取so的文件名
String filename = System.mapLibraryName(libraryName);
调用本地方法,加载so文件。
String error = nativeLoad(candidate, loader);
error为空直接返回。
1030 if (error == null) {
1031 return;
1032 }
1021 String filename = System.mapLibraryName(libraryName);
1022 List<String> candidates = new ArrayList<String>();
1023 String lastError = null;
1024 for (String directory : getLibPaths()) {
1025 String candidate = directory + filename;
1026 candidates.add(candidate);
1027
1028 if (IoUtils.canOpenReadOnly(candidate)) {
1029 String error = nativeLoad(candidate, loader);
1030 if (error == null) {
1031 return;
1032 }
1033 lastError = error;
1034 }
1035 }
1036
1037 if (lastError != null) {
1038 throw new UnsatisfiedLinkError(lastError);
1039 }
1040 throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
1041 }
我们跟踪一下如下方法
nativeLoad(candidate, loader);
nativeLoad(filename, loader);
如下方法是本地方法,逻辑用c或c++编写
1071 private static native String nativeLoad(String filename, ClassLoader loader);
这个本地方法在如下文件里
xref: /libcore/ojluni/src/main/native/Runtime.c
如下代码可以知道,这个本地方法是动态注册的。
83static JNINativeMethod gMethods[] = {
84 FAST_NATIVE_METHOD(Runtime, freeMemory, "()J"),
85 FAST_NATIVE_METHOD(Runtime, totalMemory, "()J"),
86 FAST_NATIVE_METHOD(Runtime, maxMemory, "()J"),
87 NATIVE_METHOD(Runtime, gc, "()V"),
88 NATIVE_METHOD(Runtime, nativeExit, "(I)V"),
89 NATIVE_METHOD(Runtime, nativeLoad,
90 "(Ljava/lang/String;Ljava/lang/ClassLoader;)"
91 "Ljava/lang/String;"),
92};
跟踪一下JVM_NativeLoad函数 该函数有三个参数
76JNIEXPORT jstring JNICALL
77Runtime_nativeLoad(JNIEnv* env, jclass ignored, jstring javaFilename,
78 jobject javaLoader)
79{
80 return JVM_NativeLoad(env, javaFilename, javaLoader);
81}
如下是JVM_NativeLoad函数
323JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env,
324 jstring javaFilename,
325 jobject javaLoader) {
326 ScopedUtfChars filename(env, javaFilename);
327 if (filename.c_str() == NULL) {
328 return NULL;
329 }
330
331 std::string error_msg;
332 {
333 art::JavaVMExt* vm = art::Runtime::Current()->GetJavaVM();
334 bool success = vm->LoadNativeLibrary(env,
335 filename.c_str(),
336 javaLoader,
337 &error_msg);
338 if (success) {
339 return nullptr;
340 }
341 }
342
343
344 env->ExceptionClear();
345 return env->NewStringUTF(error_msg.c_str());
346}
我们看一下如下代码
334 bool success = vm->LoadNativeLibrary(env,
335 filename.c_str(),
336 javaLoader,
337 &error_msg);
跟踪一下LoadNativeLibrary函数
854bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,
855 const std::string& path,
856 jobject class_loader,
857 std::string* error_msg) {
858 error_msg->clear();
859
860
861
862
863
864 SharedLibrary* library;
865 Thread* self = Thread::Current();
866 {
867
868 MutexLock mu(self, *Locks::jni_libraries_lock_);
869 library = libraries_->Get(path);
870 }
871 void* class_loader_allocator = nullptr;
872 {
873 ScopedObjectAccess soa(env);
874
875
876 ObjPtr<mirror::ClassLoader> loader = soa.Decode<mirror::ClassLoader>(class_loader);
877
878 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
879 if (class_linker->IsBootClassLoader(soa, loader.Ptr())) {
880 loader = nullptr;
881 class_loader = nullptr;
882 }
883
884 class_loader_allocator = class_linker->GetAllocatorForClassLoader(loader.Ptr());
885 CHECK(class_loader_allocator != nullptr);
886 }
887 if (library != nullptr) {
888
889 if (library->GetClassLoaderAllocator() != class_loader_allocator) {
890
891
892
893
894
895 auto call_to_string = [&](jobject obj) -> std::string {
896 if (obj == nullptr) {
897 return "null";
898 }
899
900 ScopedLocalRef<jobject> local_ref(env, env->NewLocalRef(obj));
901 if (local_ref != nullptr) {
902 ScopedLocalRef<jclass> local_class(env, env->GetObjectClass(local_ref.get()));
903 jmethodID to_string = env->GetMethodID(local_class.get(),
904 "toString",
905 "()Ljava/lang/String;");
906 DCHECK(to_string != nullptr);
907 ScopedLocalRef<jobject> local_string(env,
908 env->CallObjectMethod(local_ref.get(), to_string));
909 if (local_string != nullptr) {
910 ScopedUtfChars utf(env, reinterpret_cast<jstring>(local_string.get()));
911 if (utf.c_str() != nullptr) {
912 return utf.c_str();
913 }
914 }
915 env->ExceptionClear();
916 return "(Error calling toString)";
917 }
918 return "null";
919 };
920 std::string old_class_loader = call_to_string(library->GetClassLoader());
921 std::string new_class_loader = call_to_string(class_loader);
922 StringAppendF(error_msg, "Shared library \"%s\" already opened by "
923 "ClassLoader %p(%s); can't open in ClassLoader %p(%s)",
924 path.c_str(),
925 library->GetClassLoader(),
926 old_class_loader.c_str(),
927 class_loader,
928 new_class_loader.c_str());
929 LOG(WARNING) << *error_msg;
930 return false;
931 }
932 VLOG(jni) << "[Shared library \"" << path << "\" already loaded in "
933 << " ClassLoader " << class_loader << "]";
934 if (!library->CheckOnLoadResult()) {
935 StringAppendF(error_msg, "JNI_OnLoad failed on a previous attempt "
936 "to load \"%s\"", path.c_str());
937 return false;
938 }
939 return true;
940 }
941
942
943
944
945
946
947
948
949
950
951
952
953
954 ScopedLocalRef<jstring> library_path(env, GetLibrarySearchPath(env, class_loader));
955
956 Locks::mutator_lock_->AssertNotHeld(self);
957 const char* path_str = path.empty() ? nullptr : path.c_str();
958 bool needs_native_bridge = false;
959 void* handle = android::OpenNativeLibrary(env,
960 runtime_->GetTargetSdkVersion(),
961 path_str,
962 class_loader,
963 library_path.get(),
964 &needs_native_bridge,
965 error_msg);
966
967 VLOG(jni) << "[Call to dlopen(\"" << path << "\", RTLD_NOW) returned " << handle << "]";
968
969 if (handle == nullptr) {
970 VLOG(jni) << "dlopen(\"" << path << "\", RTLD_NOW) failed: " << *error_msg;
971 return false;
972 }
973
974 if (env->ExceptionCheck() == JNI_TRUE) {
975 LOG(ERROR) << "Unexpected exception:";
976 env->ExceptionDescribe();
977 env->ExceptionClear();
978 }
979
980
981 bool created_library = false;
982 {
983
984 std::unique_ptr<SharedLibrary> new_library(
985 new SharedLibrary(env,
986 self,
987 path,
988 handle,
989 needs_native_bridge,
990 class_loader,
991 class_loader_allocator));
992
993 MutexLock mu(self, *Locks::jni_libraries_lock_);
994 library = libraries_->Get(path);
995 if (library == nullptr) {
996 library = new_library.release();
997 libraries_->Put(path, library);
998 created_library = true;
999 }
1000 }
1001 if (!created_library) {
1002 LOG(INFO) << "WOW: we lost a race to add shared library: "
1003 << "\"" << path << "\" ClassLoader=" << class_loader;
1004 return library->CheckOnLoadResult();
1005 }
1006 VLOG(jni) << "[Added shared library \"" << path << "\" for ClassLoader " << class_loader << "]";
1007
1008 bool was_successful = false;
1009 void* sym = library->FindSymbol("JNI_OnLoad", nullptr);
1010 if (sym == nullptr) {
1011 VLOG(jni) << "[No JNI_OnLoad found in \"" << path << "\"]";
1012 was_successful = true;
1013 } else {
1014
1015
1016
1017
1018 ScopedLocalRef<jobject> old_class_loader(env, env->NewLocalRef(self->GetClassLoaderOverride()));
1019 self->SetClassLoaderOverride(class_loader);
1020
1021 VLOG(jni) << "[Calling JNI_OnLoad in \"" << path << "\"]";
1022 typedef int (*JNI_OnLoadFn)(JavaVM*, void*);
1023 JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
1024 int version = (*jni_on_load)(this, nullptr);
1025
1026 if (runtime_->GetTargetSdkVersion() != 0 && runtime_->GetTargetSdkVersion() <= 21) {
1027
1028 EnsureFrontOfChain(SIGSEGV);
1029 }
1030
1031 self->SetClassLoaderOverride(old_class_loader.get());
1032
1033 if (version == JNI_ERR) {
1034 StringAppendF(error_msg, "JNI_ERR returned from JNI_OnLoad in \"%s\"", path.c_str());
1035 } else if (JavaVMExt::IsBadJniVersion(version)) {
1036 StringAppendF(error_msg, "Bad JNI version returned from JNI_OnLoad in \"%s\": %d",
1037 path.c_str(), version);
1038
1039
1040
1041
1042
1043
1044 } else {
1045 was_successful = true;
1046 }
1047 VLOG(jni) << "[Returned " << (was_successful ? "successfully" : "failure")
1048 << " from JNI_OnLoad in \"" << path << "\"]";
1049 }
1050
1051 library->SetResult(was_successful);
1052 return was_successful;
1053}
定义一个共享库指针,用于存放so文件句柄
SharedLibrary* library;
调用Get函数,传入path,获得so文件指针
library = libraries_->Get(path);
如下是SharedLibrary类
67class SharedLibrary {
68 public:
69 SharedLibrary(JNIEnv* env, Thread* self, const std::string& path, void* handle,
70 bool needs_native_bridge, jobject class_loader, void* class_loader_allocator)
71 : path_(path),
72 handle_(handle),
73 needs_native_bridge_(needs_native_bridge),
74 class_loader_(env->NewWeakGlobalRef(class_loader)),
75 class_loader_allocator_(class_loader_allocator),
76 jni_on_load_lock_("JNI_OnLoad lock"),
77 jni_on_load_cond_("JNI_OnLoad condition variable", jni_on_load_lock_),
78 jni_on_load_thread_id_(self->GetThreadId()),
79 jni_on_load_result_(kPending) {
80 CHECK(class_loader_allocator_ != nullptr);
81 }
82
83 ~SharedLibrary() {
84 Thread* self = Thread::Current();
85 if (self != nullptr) {
86 self->GetJniEnv()->DeleteWeakGlobalRef(class_loader_);
87 }
88
89 android::CloseNativeLibrary(handle_, needs_native_bridge_);
90 }
91
92 jweak GetClassLoader() const {
93 return class_loader_;
94 }
95
96 const void* GetClassLoaderAllocator() const {
97 return class_loader_allocator_;
98 }
99
100 const std::string& GetPath() const {
101 return path_;
102 }
103
104
108 bool CheckOnLoadResult()
109 REQUIRES(!jni_on_load_lock_) {
110 Thread* self = Thread::Current();
111 bool okay;
112 {
113 MutexLock mu(self, jni_on_load_lock_);
114
115 if (jni_on_load_thread_id_ == self->GetThreadId()) {
116
117
118 LOG(INFO) << *self << " recursive attempt to load library " << "\"" << path_ << "\"";
119 okay = true;
120 } else {
121 while (jni_on_load_result_ == kPending) {
122 VLOG(jni) << "[" << *self << " waiting for \"" << path_ << "\" " << "JNI_OnLoad...]";
123 jni_on_load_cond_.Wait(self);
124 }
125
126 okay = (jni_on_load_result_ == kOkay);
127 VLOG(jni) << "[Earlier JNI_OnLoad for \"" << path_ << "\" "
128 << (okay ? "succeeded" : "failed") << "]";
129 }
130 }
131 return okay;
132 }
133
134 void SetResult(bool result) REQUIRES(!jni_on_load_lock_) {
135 Thread* self = Thread::Current();
136 MutexLock mu(self, jni_on_load_lock_);
137
138 jni_on_load_result_ = result ? kOkay : kFailed;
139 jni_on_load_thread_id_ = 0;
140
141
142 jni_on_load_cond_.Broadcast(self);
143 }
144
145 void SetNeedsNativeBridge(bool needs) {
146 needs_native_bridge_ = needs;
147 }
148
149 bool NeedsNativeBridge() const {
150 return needs_native_bridge_;
151 }
152
153
154 void* FindSymbol(const std::string& symbol_name, const char* shorty = nullptr)
155 REQUIRES(!Locks::mutator_lock_) {
156 return NeedsNativeBridge()
157 ? FindSymbolWithNativeBridge(symbol_name.c_str(), shorty)
158 : FindSymbolWithoutNativeBridge(symbol_name.c_str());
159 }
160
161
162 void* FindSymbolWithoutNativeBridge(const std::string& symbol_name)
163 REQUIRES(!Locks::mutator_lock_) {
164 CHECK(!NeedsNativeBridge());
165
166 return dlsym(handle_, symbol_name.c_str());
167 }
168
169 void* FindSymbolWithNativeBridge(const std::string& symbol_name, const char* shorty)
170 REQUIRES(!Locks::mutator_lock_) {
171 CHECK(NeedsNativeBridge());
172
173 uint32_t len = 0;
174 return android::NativeBridgeGetTrampoline(handle_, symbol_name.c_str(), shorty, len);
175 }
176
177 private:
178 enum JNI_OnLoadState {
179 kPending,
180 kFailed,
181 kOkay,
182 };
183
184
185 const std::string path_;
186
187
188 void* const handle_;
189
190
191 bool needs_native_bridge_;
192
193
194
195 const jweak class_loader_;
196
197
198 const void* class_loader_allocator_;
199
200
201 Mutex jni_on_load_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
202
203 ConditionVariable jni_on_load_cond_ GUARDED_BY(jni_on_load_lock_);
204
205 uint32_t jni_on_load_thread_id_ GUARDED_BY(jni_on_load_lock_);
206
207 JNI_OnLoadState jni_on_load_result_ GUARDED_BY(jni_on_load_lock_);
208};
如下函数打开so文件,返回文件句柄 有文件句柄后可以对so文件随意读写操作
959 void* handle = android::OpenNativeLibrary(env,
960 runtime_->GetTargetSdkVersion(),
961 path_str,
962 class_loader,
963 library_path.get(),
964 &needs_native_bridge,
965 error_msg);
如下函数查找JNI_Onload的位置,用于远程调用。 因为so文件本身是可执行文件, 在ida里可以看到函数等
1009 void* sym = library->FindSymbol("JNI_OnLoad", nullptr);
如下函数把JNI_Onload位置转为可调用的函数
1023 JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
开始调用,返回version
1024 int version = (*jni_on_load)(this, nullptr);
通过version判断是否成功调用该函数
if (version == JNI_ERR) {
1034 StringAppendF(error_msg, "JNI_ERR returned from JNI_OnLoad in \"%s\"", path.c_str());
1035 } else if (JavaVMExt::IsBadJniVersion(version)) {
1036 StringAppendF(error_msg, "Bad JNI version returned from JNI_OnLoad in \"%s\": %d",
1037 path.c_str(), version);
1038
1039
1040
1041
1042
1043
1044 } else {
1045 was_successful = true;
1046 }
如果执行了如下代码,说明lib库加载完成。
1052 return was_successful;
|