I have a JNI method called com.xxxxxxx.xxxxxxx.encodesdk.FdkAacEncoder#native_release
, and the relative native method is Java_com_xxxxxxx_xxxxxxx_encodesdk_FdkAacEncoder_native_1release
(Because of sensitive information, I hide the real package name, but the length is the same)
Thre JNI method works fine in most devices, but I got java.lang.UnsatisfiedLinkError
on some devices in production environment:
java.lang.UnsatisfiedLinkError: No implementation found for int com.xxxxxxx.xxxxxxx.encodesdk.FdkAacEncoder.native_release()
(tried Java_com_xxxxxxx_xxxxxxx_encodesek_FdkAacEncoder_native_1release and
Java_com_xxxxxxx_xxxxxxx_encodesdk_FdkAacEncoder_native_1release__)
Notice the first method name, encodesdk
was modified to encodesek
, I can't understand!
And I found the relative source code of Android 9.0 ART: (this crash found on Android 5.1 to Android 10)
http://androidxref.com/9.0.0_r3/xref/art/runtime/java_vm_ext.cc#249
void* FindNativeMethod(Thread* self, ArtMethod* m, std::string& detail)
REQUIRES(!Locks::jni_libraries_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
std::string jni_short_name(m->JniShortName());
std::string jni_long_name(m->JniLongName());
mirror::ClassLoader* const declaring_class_loader = m->GetDeclaringClass()->GetClassLoader();
ScopedObjectAccessUnchecked soa(Thread::Current());
void* const declaring_class_loader_allocator =
Runtime::Current()->GetClassLinker()->GetAllocatorForClassLoader(declaring_class_loader);
CHECK(declaring_class_loader_allocator != nullptr);
// TODO: Avoid calling GetShorty here to prevent dirtying dex pages?
const char* shorty = m->GetShorty();
{
// Go to suspended since dlsym may block for a long time if other threads are using dlopen.
ScopedThreadSuspension sts(self, kNative);
void* native_code = FindNativeMethodInternal(self,
declaring_class_loader_allocator,
shorty,
jni_short_name,
jni_long_name);
if (native_code != nullptr) {
return native_code;
}
}
detail += "No implementation found for ";
detail += m->PrettyMethod();
detail += " (tried " + jni_short_name + " and " + jni_long_name + ")";
}
http://androidxref.com/9.0.0_r3/xref/art/runtime/art_method.cc#801
std::string ArtMethod::JniLongName() {
std::string long_name;
long_name += JniShortName();
long_name += "__";
std::string signature(GetSignature().ToString());
signature.erase(0, 1);
signature.erase(signature.begin() + signature.find(')'), signature.end());
long_name += MangleForJni(signature);
return long_name;
}
Looks like JniLongName
is just the JniShortName
with "__" and signature (if exists). So I think if there is some bug between java_vm_ext.cc#254
to java_vm_ext.cc#272
, which makes jni_short_name
was modified?