2017-05-24 15 views
0

system_server에서 교착 상태가 발생했으며 잠금은 PackageManager에 의해 보류됩니다. GC가 차단되면 다른 JNI가 GetStringCritical 및 ReleaseStringCritical의 사이에 호출이있는 경우 GetStringCritical 원인이 교착 상태가 될 수 있습니까?

"PackageManager" prio=5 tid=27 WaitingForGcToComplete 
    | group="main" sCount=1 dsCount=0 obj=0x12d3e7b0 self=0xb865c1a0 
    | sysTid=579 nice=0 cgrp=default sched=0/0 handle=0xb865c788 
    | state=S schedstat=(82300981 68593861 146) utm=6 stm=2 core=1 HZ=100 
    | stack=0xa0fdb000-0xa0fdd000 stackSize=1036KB 
    | held mutexes= 
    native: #00 pc 00012960 /system/lib/libc.so (syscall+28) 
    native: #01 pc 000a88ad /system/lib/libart.so(art::Mutex::ExclusiveLock(art::Thread*)+364) 
    native: #02 pc 0013aa7b /system/lib/libart.so (art::gc::Heap::IncrementDisableMovingGC(art::Thread*)+90) 
    native: #03 pc 001c0329 /system/lib/libart.so (art::JNI::GetStringCritical(_JNIEnv*, _jstring*, unsigned char*)+392) 
    native: #04 pc 00082223 /system/lib/libandroid_runtime.so (???) 
    native: #05 pc 00082291 /system/lib/libandroid_runtime.so (???) 
    native: #06 pc 00263595 /data/dalvik-cache/arm/[email protected]@boot.oat (Java_android_os_Parcel_nativeWriteString__JLjava_lang_String_2+120) 
    at android.os.Parcel.nativeWriteString(Native method) 
    at android.os.Parcel.writeString(Parcel.java:542) 
    at android.content.ComponentName.writeToParcel(ComponentName.java:267) 
    at android.content.ComponentName.writeToParcel(ComponentName.java:282) 
    at android.content.Intent.writeToParcel(Intent.java:7486) 
    at android.app.ApplicationThreadProxy.scheduleUnbindService(ApplicationThreadNative.java:929) 
    at com.android.server.am.ActiveServices.removeConnectionLocked(ActiveServices.java:1842) 
    at com.android.server.am.ActiveServices.unbindServiceLocked(ActiveServices.java:943) 
    at com.android.server.am.ActivityManagerService.unbindService(ActivityManagerService.java:15787) 
    - locked <0x1d3e13e9> (a com.android.server.am.ActivityManagerService) 

그래서 내가 그것을 구글과 발견, 교착 상태가 발생할 수 있습니다. 자세한 내용을 보려면 The Java Native Interface: Programmer's Guide and Specification

이것은 frameworks \ base \ core \ jni \ android_os_Parcel.cpp의 android_os_Parcel_writeString 메소드의 일부입니다.

const jchar* str = env->GetStringCritical(val, 0); 
    if (str) { 
     err = parcel->writeString16(str, env->GetStringLength(val)); 
     env->ReleaseStringCritical(val, str); 
    } 

나는 android_os_Parcel_writeString은 매우 일반적으로 사용되는 방법이기 때문에 교착 상태가 android_os_Parcel_writeString에 의해 원인이 확실 할 수 없습니다.

그래서 android_os_Parcel_writeString이 교착 상태를 유발할 수 있습니다.

답장을 보내 주셔서 감사 드리며 어색한 영어를 잊어 버리십시오.

답변

0

GetStringCritical은주의해서 사용해야합니다. GetStringCritical을 통해 얻은 포인터를 보유하는 동안 원시 코드가 JVM에서 새 오브젝트를 할당하지 못하도록하거나 시스템이 교착 상태가 될 수있는 다른 블로킹 호출을 수행하지 않아야합니다.

/* This is not safe! */ 
const char *c_str = (*env)->GetStringCritical(env, j_str, 0); 
if (c_str == NULL) { 
... /* error handling */ 
} 
fprintf(fd, "%s\n", c_str); 
(*env)->ReleaseStringCritical(env, j_str, c_str); 

코드의 문제는 가비지 컬렉션이 현재의 thread에 의해 사용할 수 없을 때 파일 핸들에 쓸 항상 안전하지 것입니다. 예를 들어, 다른 thread Tfd 파일 핸들에서 읽기를 기다리고 있습니다. 은 fprintf 호출이 fd에서 모든 보류중인 데이터 읽기를 완료 할 때까지 기다리는 방식으로 운영 체제 버퍼링을 설정한다고 가정합시다. 은 교착 상태에 대한 가능한 시나리오를 구성했습니다. thread T이 메모리를 파일 핸들에서 읽기위한 버퍼로 사용할 메모리를 할당 할 수없는 경우 가비지 수집을 요청해야합니다. 가비지 수집 요청은 현재 스레드가 fprintf 호출이 반환 될 때까지 발생할 수없는 ReleaseStringCritical을 실행할 때까지 차단됩니다. fprintf 호출이 파일의 읽기 https://android.googlesource.com/platform/frameworks/base/+/master/core/jni/android_os_Parcel.cpp보고 후

을 처리 완료 thread T을 위해, 그러나, 대기, 방법 writeString16 무료 교착 상태입니다. 지금까지 Parcel과 관련된 문제는 전혀 볼 수 없습니다.