Sto riscontrando un problema con il convertitore dalvik dex e l'opcode che sta utilizzando per richiamare i metodi. Fondamentalmente ho un metodo private final
definito nella mia classe, e quando lo si chiama, invece di generare l'opcode invoke-direct
, dx sta generando invoke-super
. Poiché si tratta di un metodo privato, il metodo non esiste sulla super classe, quindi ricevo una violazione VFY sul dispositivo. Sono stato in grado di rintracciare lo scenario esatto che attiva questo, e sembra accadere quando:Trasformazione Dalvik tramite codice di invocazione errato
- strumentazione classi con JaCoCo e
- classi compilate con
--target 1.6
Se queste due condizioni sono soddisfatti, la classe di dex risultante ha invoke-super
anziché invoke-direct
. Se disattivo JaCoCo OR se compilo con --target 1.5
, utilizza l'opcode invoke-direct
corretto.
Nel guardare il codice della classe smontato javap
, posso vedere che cosa provoca dx
ad assumere eccellente invece di diretta:
Non strumentato, compilato per 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]
strumentati, compilato per 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, compilato per 1.6:
$ 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]
Quindi la differenza è che il bytecode Java compilato .class file è compilato che fa riferimento alla completo nome del this
di classe (avviso "//Method waitForConnectivity:()V
" class vs "//Method com/example/ClassName.waitForConnectivity:()V
"). Sembra che dx
assuma automaticamente che se il nome del metodo è pienamente qualificato, deve utilizzare invoke-super
, ma se non è qualificato, utilizza invoke-direct
.
Le mie domande sono:
- È questo un bug in Android di
dx
, o di un bug nel JaCoCo? - Come evitare questo, in modo che le classi JaCoCo-instrumented possano funzionare correttamente nei miei build di test automatici?
mia soluzione attuale è quella di avere un Maven "jacoco" profilo, e lì ho sovrascrivere la proprietà ${java.version}
di cambiarlo dal default "1.6" a "1.5". C'è una soluzione migliore?
Quindi questo implicherebbe che ref.getDefiningClass()! = Method.getDefiningClass() '. Cercherò di ottenere una discarica più completa per te da qualche tempo oggi. Ma il problema sembra essere facilmente riproducibile usando la strumentazione offline JaCoCo e il compilatore Java 1.6. È interessante notare però che non si è sempre rotto così, quindi probabilmente hai ragione che c'è anche qualcos'altro. Solo non so quando è iniziato. – Joe
Concedo il premio perché hai soddisfatto la parte credibile del requisito di taglia. Sebbene non sia stato ancora risolto o rintracciato per un motivo/causa, per ora sembra che il colpevole sia probabilmente lo strumento JaCoCo, sebbene ritenga che 'dx' dovrebbe essere ancora in grado di riconoscere che la classe che definisce il metodo invocato è uguale alla classe che definisce l'invocatore, risultante in "INVOKE_DIRECT" come previsto. Richiederà ulteriori indagini come suggerito. Forse potremo continuare in una chat in un secondo momento, poiché trovo il tempo per tornare a questo. – Joe
Grazie! Come ho detto, 'dx --dump' può probabilmente aiutare a individuare la natura esatta della differenza. Non ho intenzione di affermare che 'dx' è impeccabile (anche se l'orgoglio mi fa desiderare di farlo), ma sì, JaCoCo sta quasi certamente facendo qualcosa almeno in qualche modo sospetto. – danfuzz