Ich stoße auf ein Problem mit dem Dalvik Dex-Konverter und dem Opcode, der verwendet wird, um Methoden aufzurufen. Grundsätzlich habe ich eine private final
Methode in meiner Klasse definiert, und wenn Sie es aufrufen, anstatt invoke-direct
Opcode zu generieren, generiert dx invoke-super
. Da es sich um eine private Methode handelt, existiert die Methode nicht in der Superklasse, daher erhalte ich eine VFY-Verletzung auf dem Gerät. Ich war in der Lage, die genaue Szenario auf die Spur, die dies auslöst, und es scheint zu geschehen, wenn:Dalvik-Transformation mit falschem Invoke-Opcode
- die Klassen mit JaCoCo instrumentiert und
- Klassen zusammengestellt mit
--target 1.6
Wenn diese beiden Bedingungen erfüllt sind, hat die resultierende Dex-Klasse invoke-super
statt invoke-direct
. Wenn ich JaCoCo ODER deaktivieren, wenn ich mit --target 1.5
kompiliere, verwendet es den korrekten invoke-direct
Opcode.
am javap
zerlegten Klassencode In suchen, kann ich sehen, was dx
Super statt direkt zu übernehmen Ursachen:
nicht instrumentiert, zusammengestellt für 1,6:
$ javap -d com.example.ClassName | grep waitForConnectivity
159: invokespecial #115; //Method waitForConnectivity:()V
$ dexdump -d classes.dex | grep waitForConnectivity
147ad8: 7010 6042 0200 |001e: invoke-direct {v2}, Lcom/example/ClassName;.waitForConnectivity:()V // [email protected]
instrumentiert, zusammengestellt für 1,5 (--target 1.5
):
$ javap -d com.example.ClassName | grep waitForConnectivity
235: invokespecial #115; //Method waitForConnectivity:()V
$ dexdump -d classes.dex | grep waitForConnectivity
149d4c: 7010 9242 0400 |0018: invoke-direct {v4}, Lcom/example/ClassName;.waitForConnectivity:()V // [email protected]
Instrumented, für 1.6 zusammengestellt:
$ javap -d com.example.ClassName | grep waitForConnectivity
235: invokespecial #115; //Method com/example/ClassName.waitForConnectivity:()V
$ dexdump -d classes.dex | grep waitForConnectivity
149d4c: 6f10 9242 0400 |0018: invoke-super {v4}, Lcom/example/ClassName;.waitForConnectivity:()V // [email protected]
So ist der Unterschied besteht darin, dass die kompilierte Class-Datei hat Bytecode kompiliert Java, die die vollständig qualifizierten Klassennamen der this
Klasse (Hinweis "//Method waitForConnectivity:()V
" verweist vs "//Method com/example/ClassName.waitForConnectivity:()V
"). Es scheint, dass dx
automatisch davon ausgeht, dass, wenn der Methodenname vollständig qualifiziert ist, es invoke-super
verwenden muss, aber wenn es nicht qualifiziert ist, verwendet es invoke-direct
.
Meine Fragen sind:
- Ist das ein Bug in Android
dx
oder einen Fehler in JaCoCo? - Wie kann ich dies vermeiden, damit die mit JaCoCo instrumentierten Klassen in meinen automatisierten Testaufbauten ordnungsgemäß funktionieren?
Meine aktuelle Problemumgehung ist ein Maven „jacoco“ Profil haben, und ich überschreiben die ${java.version}
Eigenschaft in dort sind es von der Standardeinstellung zu ändern „1,6“ bis „1,5“. Gibt es eine bessere Lösung?
Dies würde bedeuten, dass 'ref.getDefiningClass()! = Method.getDefiningClass()'. Ich werde heute versuchen, eine vollständigere Dump für Sie zu bekommen. Aber das Problem scheint mit der Offline-Instrumentierung von JaCoCo und dem Java 1.6 Compiler leicht reproduzierbar zu sein. Interessanterweise brach es nicht immer so, also hast du wahrscheinlich recht, dass da noch etwas anderes vor sich geht. Ich weiß nur nicht wann es angefangen hat. – Joe
Ich gewähre das Kopfgeld, weil Sie den glaubwürdigen Teil der Bounty-Anforderung erfüllt haben. Obwohl es noch nicht aufgelöst oder auf einen Grund zurückverfolgt wurde, scheint es, dass der Schuldige höchstwahrscheinlich der JaCoCo-Instrumentierer ist, obwohl ich denke, dass "dx" immer noch in der Lage sein sollte, die definierende Klasse für die aufgerufene Methode zu erkennen ist gleich der definierenden Klasse des Aufrufers, was wie erwartet zu 'INVOKE_DIRECT' führt. Wird wie vorgeschlagen weitere Untersuchungen erfordern. Vielleicht können wir das später in einem Chat fortsetzen, da ich Zeit finde, darauf zurückzukommen. – Joe
Danke! Wie ich schon sagte, kann 'dx - dump' wahrscheinlich helfen, die genaue Art des Unterschieds zu bestimmen. Ich werde nicht behaupten, dass "dx" fehlerfrei ist (obwohl Stolz mich dazu bringen will), aber ja, JaCoCo macht mit Sicherheit etwas, das zumindest etwas verdächtig ist. – danfuzz