JNI奔潰

accessed stale WeakGlobal 0xffffffff

  • 奔潰信息
indirect_reference_table.cc:61] JNI ERROR (app bug): accessed stale WeakGlobal 0xffffffff (index 268435455 in a table of size 81)
runtime.cc:647] Runtime aborting...
runtime.cc:647] All threads:
runtime.cc:647] DALVIK THREADS (45):
runtime.cc:647] "Thread-4" prio=5 tid=23 Runnable
runtime.cc:647] | group="" sCount=0 dsCount=0 flags=0 obj=0x18f41408 self=0xbf3eec00
runtime.cc:647] | sysTid=23288 nice=0 cgrp=default sched=0/0 handle=0xbaad8230
runtime.cc:647] | state=R schedstat=( 419543734 128472935 1197 ) utm=37 stm=4 core=6 HZ=100
runtime.cc:647] | stack=0xba9dd000-0xba9df000 stackSize=1008KB
runtime.cc:647] | held mutexes= "abort lock" "mutator lock"(shared held)
runtime.cc:647] native: #00 pc 0030a5df /apex/com.android.runtime/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, int, BacktraceMap*, char const*, art::ArtMethod*, void*, bool)+78)
runtime.cc:647] native: #01 pc 003c03cd /apex/com.android.runtime/lib/libart.so (art::Thread::DumpStack(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, bool, BacktraceMap*, bool) const+360)
runtime.cc:647] native: #02 pc 003bcb93 /apex/com.android.runtime/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, bool, BacktraceMap*, bool) const+34)
runtime.cc:647] native: #03 pc 003d5921 /apex/com.android.runtime/lib/libart.so (art::DumpCheckpoint::Run(art::Thread*)+600)
runtime.cc:647] native: #04 pc 003d0241 /apex/com.android.runtime/lib/libart.so (art::ThreadList::RunCheckpoint(art::Closure*, art::Closure*)+296)
runtime.cc:647] native: #05 pc 003cf7e5 /apex/com.android.runtime/lib/libart.so (art::ThreadList::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, bool)+1016)
runtime.cc:647] native: #06 pc 0038ef77 /apex/com.android.runtime/lib/libart.so (art::Runtime::Abort(char const*)+1258)
runtime.cc:647] native: #07 pc 0000859b /system/lib/libbase.so (android::base::LogMessage::~LogMessage()+418)
runtime.cc:647] native: #08 pc 001e94a9 /apex/com.android.runtime/lib/libart.so (art::IndirectReferenceTable::AbortIfNoCheckJNI(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&)+168)
runtime.cc:647] native: #09 pc 00298913 /apex/com.android.runtime/lib/libart.so (art::IndirectReferenceTable::GetChecked(void*) const+278)
runtime.cc:647] native: #10 pc 002951d3 /apex/com.android.runtime/lib/libart.so (art::JavaVMExt::DecodeWeakGlobal(art::Thread*, void*)+18)
runtime.cc:647] native: #11 pc 003c4cc3 /apex/com.android.runtime/lib/libart.so (art::Thread::DecodeJObject(_jobject*) const+190)
runtime.cc:647] native: #12 pc 0029efa9 /apex/com.android.runtime/lib/libart.so (art::JNI::IsSameObject(_JNIEnv*, _jobject*, _jobject*)+424)
  • 解決思路
    通過閱讀Android源碼知道根本原因是不存在這個引用,並且這個引用的地址是0xffffffff。然後我在調用JNI方法之前打印了一下這個jstring類型,果然是0xffffffff。然後再進一步閱讀調用這個Native方法的相關代碼,發現是在解析參數的時候類型不匹配導致的。
inline bool IndirectReferenceTable::GetChecked(IndirectRef iref) const {
   ...
  const uint32_t top_index = segment_state_.top_index;
  uint32_t idx = ExtractIndex(iref);
  if (UNLIKELY(idx >= top_index)) {
    std::string msg = android::base::StringPrintf("JNI ERROR (app bug): accessed stale %s %p (index %d in a table of size %d)", GetIndirectRefKindString(kind_), iref, idx, top_index);
    AbortIfNoCheckJNI(msg);
    return false;
  }
  ...
  return true;
}

void BuildArgArrayFromVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, ObjPtr<mirror::Object> receiver, va_list ap)
    REQUIRES_SHARED(Locks::mutator_lock_) {
        // Set receiver if non-null (method is not static)
        if (receiver != nullptr) {
            Append(receiver);
        }
        for (size_t i = 1; i < shorty_len_; ++i) {
            switch (shorty_[i]) {
                case 'Z':
                case 'B':
                case 'C':
                case 'S':
                case 'I':
                    Append(va_arg(ap, jint));
                    break;
                case 'F':
                    AppendFloat(va_arg(ap, jdouble));
                    break;
                case 'L':
                    Append(soa.Decode<mirror::Object>(va_arg(ap, jobject)));
                    break;
                case 'D':
                    AppendDouble(va_arg(ap, jdouble));
                    break;
                case 'J':
                    AppendWide(va_arg(ap, jlong));
                    break;
#ifndef NDEBUG
                default:
                    LOG(FATAL) << "Unexpected shorty character: " << shorty_[i];
#endif
            }
        }
    }
}

JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid, va_list args) {
  // We want to make sure that the stack is not within a small distance from the
  // protected region in case we are calling into a leaf function whose stack
  // check has been elided.
  if (UNLIKELY(__builtin_frame_address(0) < soa.Self()->GetStackEnd())) {
    ThrowStackOverflowError(soa.Self());
    return JValue();
  }

  ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object>(obj);
  ArtMethod* method = FindVirtualMethod(receiver, jni::DecodeArtMethod(mid));
  bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
  if (is_string_init) {
    // Replace calls to String.<init> with equivalent StringFactory call.
    method = WellKnownClasses::StringInitToStringFactory(method);
    receiver = nullptr;
  }
  uint32_t shorty_len = 0;
  const char* shorty = method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len);
  JValue result;
  ArgArray arg_array(shorty, shorty_len);
  arg_array.BuildArgArrayFromVarArgs(soa, receiver, args);
  InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
  if (is_string_init) {
    // For string init, remap original receiver to StringFactory result.
    UpdateReference(soa.Self(), obj, result.GetL());
  }
  return result;
}

JNI DETECTED ERROR IN APPLICATION: mid == null

  • 奔潰信息
Accessing hidden method Landroid/graphics/GraphicBuffer;->create(IIII)Landroid/graphics/GraphicBuffer; (greylist-max-o, JNI, allowed)
ioctl c0044901 failed with code -1: Not a typewriter
Accessing hidden method Landroid/graphics/GraphicBuffer;->lockCanvas()Landroid/graphics/Canvas; (greylist-max-o, JNI, allowed)
java_vm_ext.cc:570] JNI DETECTED ERROR IN APPLICATION: mid == null
java_vm_ext.cc:570] in call to CallStaticObjectMethodV
  • 解決思路
    • 看奔潰信息能很明確的直到是在調用CallStaticObjectMethod這個方法奔潰了,而且根據堆棧也很容易知道是那個地方調用的。
    • 在runtime源碼中找到JNI DETECTED ERROR IN APPLICATION: mid == null打印的地方,這個mid就是方法ID,所以問題就GetStaticMethodID返回的mid是空的。
    • 通過閱讀官方文檔知道在7.0的時候就已經禁止訪問非公開的NDK接口了。
    • 調用JNI接口的錯誤信息可以通過ExceptionDescribe獲取,獲取到的錯誤信息是last system error: 25
    • 然後我們man errno就可以知道具體錯誤是25 ENOTTY Inappropriate ioctl for device. A control function (see ioctl(2)) was attempted for a file or special device for which the operation was inappropriate.,也就是說我們沒有權利訪問某些特殊設備。
發佈了60 篇原創文章 · 獲贊 47 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章