2017-05-24 3 views
0

Es ist ein Deadlock in system_server aufgetreten, und die Sperre wird von PackageManager gehalten.Kann GetStringCritical Deadlock verursachen?

"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) 

ich google es also und herauszufinden, ob einige andere JNI gibt es zwischen GetStringCritical und ReleaseStringCritical nennt, kann Deadlock auftreten, wenn GC gesperrt. Für weitere Details siehe The Java Native Interface: Programmer's Guide and Specification

Dies ist Teil der Methode android_os_Parcel_writeString in frameworks \ base \ core \ jni \ android_os_Parcel.cpp.

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

Ich kann nicht sicher Deadlock Ursache von android_os_Parcel_writeString ist, weil android_os_Parcel_writeString eine sehr häufig verwendete Methode ist.

Also ich frage, ist android_os_Parcel_writeString kann Deadlock verursachen?

Vielen Dank für Ihre Antwort und vergessen Sie meine peinliche Englisch.

Antwort

0

GetStringCritical muss mit äußerster Vorsicht verwendet werden. Sie müssen sicherstellen, dass der native Code beim Halten eines durch GetStringCritical erhaltenen Zeigers keine neuen Objekte in der JVM zuweist oder andere blockierende Aufrufe durchführt, die zum Deadlock des Systems führen können.

/* 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); 

Das Problem mit dem Code ist, dass es nicht immer sicher ist, in eine Datei Griff zu schreiben, wenn Speicherbereinigungs durch den aktuellen Thread deaktiviert. Für Beispiel, dass eine andere thread T darauf wartet, aus der fd Datei-Handle zu lesen. Lassen Sie uns weiter davon ausgehen, dass die Betriebssystempufferung so eingerichtet ist, dass der fprintf Aufruf wartet, bis die thread T das Lesen aller anstehenden Daten von fd beendet. Wir haben ein mögliches Szenario für Deadlocks erstellt: Wenn nicht genügend Speicherplatz zuweisen kann, um als ein Puffer für das Lesen aus der Datei behandeln dienen, muss es eine Garbage Collection anfordern. Die Speicherbereinigungsanforderung wird blockiert, bis der aktuelle Thread ReleaseStringCritical ausführt, was nicht passieren kann, bis der fprintf Aufruf zurückgibt. Der fprintf Anruf wartet jedoch für thread T Lesen aus der Datei

Griff bei https://android.googlesource.com/platform/frameworks/base/+/master/core/jni/android_os_Parcel.cpp

Nach einem Blick zu beenden, ist die Methode writeString16 frei Deadlock. Ich sehe nie ein Problem mit Parcel bis jetzt.