0

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?

sickworm
  • 31
  • 5
  • `FdkAacEncoder.native_release()` & `FdkAacEncoder_native_1release`, I see the relative method is named `1release`. The method names should be same. – Darshan Dec 24 '20 at 12:21
  • @DarShan it should have `1`. `1` follows `_` for distinguish between `_` in the JNI method name and `_` to separate the package name – sickworm Dec 24 '20 at 12:27
  • make sure that `private native void native_release();` and `Java_com_xxxxxxx_xxxxxxx_encodesdk_FdkAacEncoder_native_1release` should have same method name and same package. You can't create different method name. In c file the method should be `Java_com_xxxxxxx_xxxxxxx_encodesdk_FdkAacEncoder_native_release(JNIEnv *env, jobject instance,...)`. Also make sure you are declaring `native_release()` in this class `com.xxxxxxx.xxxxxxx.encodesdk.FdkAacEncoder` – Priyanka Dec 24 '20 at 12:38
  • @Priyankagb that's not the problem. see this: [link](https://stackoverflow.com/questions/16069209/invoking-jni-functions-in-android-package-name-containing-underscore) – sickworm Dec 25 '20 at 02:38

0 Answers0