Transformación de Dalvik usando código de invocación incorrecto

Estoy corriendo en un problema con el convertidor dalvik dex y el opcode que está utilizando para invocar métodos. Básicamente tengo un método private final definido en mi clase, y cuando lo llamo, en lugar de generar el código operativo invoke-direct , dx está generando invoke-super . Debido a que es un método privado, el método no existe en la superclase, por lo que obtengo una violación VFY en el dispositivo. Pude rastrear el escenario exacto que desencadena esto, y parece que sucede cuando:

  1. Instrumentación de las clases con JaCoCo, y
  2. Clases compiladas con --target 1.6

Si se cumplen estas dos condiciones, la clase dex resultante tiene invoke-super lugar de invoke-direct . Si desactivo JaCoCo O si compile con --target 1.5 , usa el opcode correcto de invoke-direct .

Al mirar el código de clase javap desmontado, puedo ver lo que hace dx asumir super en lugar de directo:

No instrumentado, compilado para 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 

Instrumentado, compilado para 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 

Instrumentado, compilado para 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 

Así que la diferencia es que el archivo .class compilado ha compilado bytecode java que hace referencia al nombre de clase totalmente calificado de this clase (aviso " //Method waitForConnectivity:()V " vs " //Method com/example/ClassName.waitForConnectivity:()V "). Parece que dx asume automáticamente que si el nombre del método está completamente calificado, debe usar invoke-super , pero si no está calificado, usa invoke-direct .

Mis preguntas son:

  1. ¿Se trata de un error en el dx de Android, o un error en JaCoCo?
  2. ¿Cómo puedo evitar esto, para que las clases instrumentadas con JaCoCo funcionen correctamente en mis compilaciones de prueba automatizadas?

Mi solución actual es tener un perfil "jacoco" de Maven, y en ese caso ${java.version} propiedad ${java.version} para cambiarla del valor predeterminado "1.6" a "1.5". ¿Hay alguna solución mejor?

Una de las reglas que dx utiliza para determinar si debe emitir invoke-super o invoke-direct es si cree que la llamada al método se está realizando en la misma clase que la que realiza la llamada. Vea RopperMachine.java en la fuente, alrededor de la línea 912, incluida aquí como referencia:

  case ByteOps.INVOKESPECIAL: { /* * Determine whether the opcode should be * INVOKE_DIRECT or INVOKE_SUPER. See vmspec-2 section 6 * on "invokespecial" as well as section 4.8.2 (7th * bullet point) for the gory details. */ CstMethodRef ref = (CstMethodRef) cst; if (ref.isInstanceInit() || (ref.getDefiningClass() == method.getDefiningClass()) || !method.getAccSuper()) { return RegOps.INVOKE_DIRECT; } return RegOps.INVOKE_SUPER; 

Sería interesante ver un volcado más completo de la clase que está siendo malconvertida. Creo que es probablemente el caso de que lo que está viendo desde javap no es una imagen completa de la realidad. Tenga en cuenta que dx sí tiene un descargador de archivos .class integrado en él que proporciona mucho más detalle que javap . dx --dump --bytes path/to/Name.class como dx --dump --bytes path/to/Name.class .

  • ¿Cómo puedo ejecutar Jacoco en android studio para la cobertura de código
  • JaCoCo no trabaja con pruebas Robolectric
  • La cobertura de Jacoco no funciona con el plugin android más reciente
  • 0% de cobertura de código en las pruebas de café exprés con JaCoCo y Gradle
  • Ejecutar una sola prueba para comprobar la cobertura de código Jacoco Android
  • Cómo personalizar Jacoco para las pruebas de Espresso en Android
  • Cobertura de código Jacoco en Android Studio con sabores
  • Jacoco con Gradle 0.10.0: Objeto remoto no existe
  • Jacoco con Android Gradle 1.3.0
  • Cobertura de Jacoco para la declaración de switch
  • La cobertura general de Sonarqube no coincide con la cobertura de informes de jacoco
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.