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.
,也就是說我們沒有權利訪問某些特殊設備。