dalvik dex コンバーターとメソッドの呼び出しに使用しているオペコードに問題があります。基本的にprivate final
、クラスで定義されたメソッドがあり、それを呼び出すと、invoke-direct
オペコードを生成する代わりに、dx が生成されinvoke-super
ます。プライベート メソッドであるため、スーパー クラスにはメソッドが存在しないため、デバイスで VFY 違反が発生します。これをトリガーする正確なシナリオを突き止めることができました。次の場合に発生するようです。
- JaCoCo を使用してクラスをインストルメント化し、
- でコンパイルされたクラス
--target 1.6
これら 2 つの条件が満たされている場合、結果の dex クラスにはinvoke-super
代わりにinvoke-direct
. JaCoCo を無効にすると、または でコンパイルすると--target 1.5
、正しいinvoke-direct
オペコードが使用されます。
javap
逆アセンブルされたクラス コードを見るdx
と、直接ではなくスーパーを想定する原因がわかります。
インストルメント化されていない、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 // method@4260
インストルメント化、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 // method@4292
インストルメント化、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 // method@4292
したがって、違いは、コンパイルされた .class ファイルが、クラスの完全修飾クラス名を参照する Java バイトコードをコンパイルしたことです (" " と " "this
に注意してください)。メソッド名が完全修飾されている場合は を使用する必要があると自動的に想定しているように見えますが、修飾されていない場合は を使用します。//Method waitForConnectivity:()V
//Method com/example/ClassName.waitForConnectivity:()V
dx
invoke-super
invoke-direct
私の質問は次のとおりです。
- これは Android の
dx
バグですか、それとも JaCoCo のバグですか? - 自動化されたテスト ビルドで JaCoCo がインストルメント化されたクラスを適切に動作させるには、どうすればこれを回避できますか?
私の現在の回避策は、Maven の「jacoco」プロファイルを使用することです。そこで${java.version}
プロパティをオーバーライドして、デフォルトの「1.6」から「1.5」に変更します。より良い解決策はありますか?