У меня возникла проблема с конвертером dalvik dex и кодом операции, который он использует для вызова методов. По сути, у меня есть метод private final
, определенный в моем классе, и при его вызове вместо генерации кода операции invoke-direct
dx генерирует invoke-super
. Поскольку это закрытый метод, метод не существует в суперклассе, поэтому я получаю нарушение VFY на устройстве. Я смог отследить точный сценарий, который вызывает это, и, похоже, это происходит, когда:
- инструментирование классов с помощью JaCoCo, и
- классы, скомпилированные с помощью
--target 1.6
Если эти два условия соблюдены, результирующий класс dex имеет invoke-super
вместо invoke-direct
. Если я отключу JaCoCo ИЛИ если я скомпилирую с --target 1.5
, он использует правильный код операции invoke-direct
.
Глядя на дизассемблированный код класса javap
, я вижу, что заставляет dx
принимать super вместо direct:
Не инструментировано, скомпилировано для версии 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». Есть ли лучшее решение?