art_quick_invoke_interface_trampoline crash问题分析

问题现象

最近收到客户反馈的一个第三方App几乎必现bug.

  • 复现步骤
    • 手机(Android 6.0, 32bit CPU)
    • 刷上gms版本
    • 连上翻墙wifi, 打开play store, 提示升级
    • 下载并安装第三方App: com.flipkart.android
    • 打开App后,必现crash

定位分析

  • 相关log
    • tombstone
      Revision: '0'
      ABI: 'arm' 
      pid: 13920, tid: 13971, name: AsyncTask #5  >>> com.flipkart.android <<<
      signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xf10174
          r0 00f100f8  r1 a3ef3758  r2 00f100f8  r3 f4281c35
          r4 b6ce7e40  r5 a3ef3794  r6 b6ce7e40  r7 a3ef37b0
          r8 a3ef37a0  r9 71d96009  sl a3ef37ac  fp a3ef37ac
          ip b4df5918  sp a3ef3720  lr b4d0283f  pc b4c4ae76  cpsr 600b0030
          d0  746e656d656c7063  d1  6920746f6e207365
          d2  6c61757472695620  d3  45656e6968636127
          d4  a3ef3ad8b4dc0528  d5  b4daa770b4daaa1c
          d6  b4daa940b4daaa44  d7  0000000100000000
          d8  0000000000000000  d9  0000000000000000
          d10 0000000000000000  d11 0000000000000000
          d12 0000000000000000  d13 0000000000000000
          d14 0000000000000000  d15 0000000000000000
          d16 0000000000000000  d17 0000000000000000
          d18 e4025aaef5998db7  d19 84009a117711baf7
          d20 5a83f99993847c9a  d21 5a8279995a827999
          d22 8ecb34b68517d7d5  d23 267b77fb9a502286
          d24 93ce4760edb98983  d25 5104571b527b7b18
          d26 199bdf588148e7e5  d27 0e741e431450ae37
          d28 5a8279995a827999  d29 5a8279995a827999
          d30 0000000000000000  d31 0000000000000000
          scr 20000010
      
      backtrace:
          #00 pc 002a1e76  /system/lib/libart.so (_ZN3art6mirror5Class13GetDescriptorEPNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE+17)
          #01 pc 0035983b  /system/lib/libart.so (_ZN3art16PrettyDescriptorEPNS_6mirror5ClassE+30)
          #02 pc 000a6ded  /system/lib/libart.so (_ZN3art58ThrowIncompatibleClassChangeErrorClassForInterfaceDispatchEPNS_9ArtMethodEPNS_6mirror6ObjectES1_+236)
          #03 pc 003e747b  /system/lib/libart.so (artInvokeInterfaceTrampoline+110)
          #04 pc 000e6579  /system/lib/libart.so (art_quick_invoke_interface_trampoline+40)
          #05 pc 71dc4af7  /data/dalvik-cache/arm/system@framework@boot.oat (offset 0x1faf000)
      

初步分析

  • gdb堆栈
    (gdb) bt
    #0  std::__1::__c11_atomic_load<int> (__order=std::__1::memory_order_relaxed, __a=0xf10174) at external/libcxx/include/atomic:667
    #1  std::__1::__atomic_base<int, false>::load (__m=std::__1::memory_order_relaxed, this=0xf10174) at external/libcxx/include/atomic:845
    #2  art::Atomic<int>::LoadJavaData (this=0xf10174) at art/runtime/atomic.h:207
    #3  art::mirror::Object::GetField<int, false> (field_offset=..., this=0xf100f8) at art/runtime/mirror/object-inl.h:738
    #4  art::mirror::Object::GetField32<(art::VerifyObjectFlags)0, false> (field_offset=..., this=0xf100f8) at art/runtime/mirror/object-inl.h:598
    #5  art::mirror::Class::GetPrimitiveType<(art::VerifyObjectFlags)0> (this=0xf100f8) at art/runtime/mirror/class-inl.h:556
    #6  art::mirror::Class::IsPrimitive<(art::VerifyObjectFlags)0> (this=0xf100f8) at art/runtime/mirror/class.h:346
    #7  art::mirror::Class::GetDescriptor (this=0xf100f8, storage=storage@entry=0xa3ef3758) at art/runtime/mirror/class.cc:715
    #8  0xb4d0283e in art::PrettyDescriptor (klass=<optimized out>) at art/runtime/utils.cc:218
    #9  0xb4a4fdf0 in art::ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch (interface_method=interface_method@entry=0x71d96009, this_object=<optimized out>, referrer=referrer@entry=0x6fd39b80) at art/runtime/common_throws.cc:221
    #10 0xb4d9047e in art::artInvokeInterfaceTrampoline (interface_method=0x71d96009, this_object=0x12e01300, caller_method=0x6fd39b80, self=0xb9b169b8, sp=0xa3ef3980) at art/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc:2060
    #11 0xb4a8f57c in art_quick_invoke_interface_trampoline () at art/runtime/arch/arm/quick_entrypoints_arm.S:350
    #12 0x71dc4af8 in ?? ()
    
  • 分析
    • #0反汇编分析

      (gdb) disas
      Dump of assembler code for function art::mirror::Class::GetDescriptor(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*):
         0xb4c4ae64 <+0>: stmdb   sp!, {r4, r5, r6, r7, r8, lr}
        0xb4c4ae68 <+4>:  sub sp, #32
         0xb4c4ae6a <+6>: ldr r4, [pc, #428]  ; (0xb4c4b018 <art::mirror::Class::GetDescriptor(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)+436>)
         0xb4c4ae6c <+8>: mov r2, r0
         0xb4c4ae6e <+10>:    add r4, pc
         0xb4c4ae70 <+12>:    ldr r4, [r4, #0]
         0xb4c4ae72 <+14>:    ldr r3, [r4, #0]
         0xb4c4ae74 <+16>:    str r3, [sp, #28]
      => 0xb4c4ae76 <+18>:    ldr r5, [r0, #124]  ; 0x7c
         ... ...
      

      从这里分析来看,art::mirror::Class::GetDescriptor()的r0 = 0x00f100f8是导致问题出现的直接原因

    • r0的传递

      r0最终是通过#11传入的, 而r0来自r9的第一个内存单元值

      (gdb) x /4xw 0x71d96009
      0x71d96009: Cannot access memory at address 0x71d96009
      

      这里可以通过tombstone打印的寄存器值查看

      71d96008 f100f8d0 0000be00 c004f8d0 f104f8dc  ................
      71d96018 0000be00 00000000 f1d8f8d9 0000be00  ................
      71d96028 f23cf8d9 0000be00 f240f8d9 0000be00  ..<.......@.....
      71d96038 f244f8d9 0000be00 001f8ec1 0002b789  ..D.............
      71d96048 0054f764 00000000 00000000 00000000  d.T.............
      71d96058 00000004 00004770 00000000 00000000  ....pG..........
      71d96068 00000000 00000080 00004de0 ffff0000  .........M......
      71d96078 00000076 4de0e92d 8a10ed2d 9000b089  v...-..M-.......
      71d96088 1084f8cd 0c01f04f c008f8cd c0c4f8d9  ....O...........
      71d96098 c004f8cd 0c04f20d c0c4f8c9 c084f8dd  ................
      71d960a8 c00cf8cd d08cf8c9 f8d04648 47e0c1c0  ........HF.....G
      71d960b8 a9039004 009cf8d9 c000f8dd c020f8dc  .............. .
      71d960c8 990447e0 f8d2464a 47e0c1d0 c084f8d9  .G..JF.....G....
      71d960d8 0f00f1bc b009d104 8a10ecbd 8de0e8bd  ................
      
      

      可以看到

      • 出错的原因

        • [0x71d96009] = 0x00f100f8
        • [0x00f100f8 + 124] = [0xf10174],非法内存地址
      • r9 = 0x71d96009本身是非4字节对齐的

      • r9代表ArtMethod,其内容不是ArtMethod的正常值

      • r9位于boot.oat,这也是异常的

        71d96000-73578000 r-xp 01faf000 b3:18 58373      /data/dalvik-cache/arm/system@framework@boot.oat
        

对比实验

刷上我司的基线版本,无论是否有gms, 都无法复现.

深入分析

前面分析了libart.so的相关堆栈,还需要深入分析boot.oat是怎么传输过来的ArtMethod异常值.

  • #12分析

    • pc offset

      0x71dc4af7 - 0x6fde7000 - 0x1000 = 0x1fdcaf7

    • 对应函数

      public Throwable(String detailMessage) {
          this.detailMessage = detailMessage;
          this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT;
          fillInStackTrace();
      }
      
    • native code

      ... ...
      0x01fdcaea: 1c29          mov     r1, r5
      0x01fdcaec: 6808          ldr     r0, [r1, #0]
      0x01fdcaee: f8d001bc      ldr.w   r0, [r0, #444]
      0x01fdcaf2: f8d0e024      ldr.w   lr, [r0, #36]
      0x01fdcaf6: 47f0          blx     lr
      ... ...
      
    • 分析

      r1 = r5 = 0x12e01300
      
      (gdb) x /4xw 0x12e01300
      0x12e01300:     0x6f980410      0x00000000      0x12e01300      0x12c3d4f0
      r0 = 0x6f980410
      
      (gdb) x /4xw 0x6f980410+444
      0x6f9805cc:     0x6fdaa678      0x6fdaa678      0x6fdaa678      0x6fdaa678
      r0 = [0x6f980410 + 444] = 0x6fdaa678
      
      (gdb) x /4xw 0x6fdaa678+36
      0x6fdaa69c:     0x71d96029      0x00000000      0x00000000      0x00000000
      lr = [0x6fdaa678 + 36] = 0x71d96029
      
      offset = 0x71d96029 - 0x6fde7000 - 0x1000 = 0x1fae029
      正好对应 art_quick_imt_conflict_trampoline
         
      Throwable构造函数调用fillInStackTrace(), 编译出的native code却跳转到art_quick_imt_conflict_trampoline(),这里说不通.
      
  • 排查r5对象

    • 查看r5对象
      (gdb) p /x *('art::mirror::Throwable' *)0x12e01300
      $74 = {
       <art::mirror::Object> = {
      static kVTableLength = 0xb, 
      static hash_code_seed = {
        <std::__1::atomic<unsigned int>> = {
          <std::__1::__atomic_base<unsigned int, true>> = {
            <std::__1::__atomic_base<unsigned int, false>> = {
              __a_ = {
                __a_value = 0x473265d8
              }
            }, <No data fields>}, <No data fields>}, <No data fields>}, 
      klass_ = {
        <art::mirror::ObjectReference<false, art::mirror::Class>> = {
          reference_ = 0x6f980410
        }, <No data fields>}, 
      monitor_ = 0x0
      }, 
      members of art::mirror::Throwable: 
      cause_ = {
      <art::mirror::ObjectReference<false, art::mirror::Throwable>> = {
        reference_ = 0x12e01300
      }, <No data fields>}, 
      detail_message_ = {
      <art::mirror::ObjectReference<false, art::mirror::String>> = {
        reference_ = 0x12c3d4f0
      }, <No data fields>}, 
      stack_state_ = {
      <art::mirror::ObjectReference<false, art::mirror::Object>> = {
        reference_ = 0x0
      }, <No data fields>}, 
      stack_trace_ = {
      <art::mirror::ObjectReference<false, art::mirror::Object>> = {
        reference_ = 0x6f905e08
      }, <No data fields>}, 
      suppressed_exceptions_ = {
      <art::mirror::ObjectReference<false, art::mirror::Object>> = {
        reference_ = 0x6f905c78
      }, <No data fields>}, 
      static java_lang_Throwable_ = {
      root_ = {
        <art::mirror::ObjectReference<false, art::mirror::Object>> = {
          reference_ = 0x6f9680d0
        }, <No data fields>}
       }
      }
      
    • 查看对应的Class
      (gdb) p /x *('art::mirror::Class' *)0x6f980410
      $89 = {
      <art::mirror::Object> = {
      static kVTableLength = 0xb, 
      static hash_code_seed = {
        <std::__1::atomic<unsigned int>> = {
          <std::__1::__atomic_base<unsigned int, true>> = {
            <std::__1::__atomic_base<unsigned int, false>> = {
              __a_ = {
                __a_value = 0x473265d8
              }
            }, <No data fields>}, <No data fields>}, <No data fields>}, 
      klass_ = {
        <art::mirror::ObjectReference<false, art::mirror::Class>> = {
          reference_ = 0x6f95d1b8
        }, <No data fields>}, 
      monitor_ = 0x0
      }, 
      members of art::mirror::Class: 
      static kClassWalkSuper = 0xc0000000, 
      static kImtSize = 0x40, 
      class_loader_ = {
      <art::mirror::ObjectReference<false, art::mirror::ClassLoader>> = {
        reference_ = 0x0
      }, <No data fields>}, 
      component_type_ = {
      <art::mirror::ObjectReference<false, art::mirror::Class>> = {
        reference_ = 0x0
      }, <No data fields>}, 
      dex_cache_ = {
      <art::mirror::ObjectReference<false, art::mirror::DexCache>> = {
        reference_ = 0x6f8cafe0
      }, <No data fields>}, 
      dex_cache_strings_ = {
      <art::mirror::ObjectReference<false, art::mirror::ObjectArray<art::mirror::String> >> = {
        reference_ = 0x6f3ddae8
      }, <No data fields>}, 
      iftable_ = {
      <art::mirror::ObjectReference<false, art::mirror::IfTable>> = {
        reference_ = 0x6f8cbd48
      }, <No data fields>}, 
      name_ = {
      <art::mirror::ObjectReference<false, art::mirror::String>> = {
        reference_ = 0x6f62c478
      }, <No data fields>}, 
      super_class_ = {
      <art::mirror::ObjectReference<false, art::mirror::Class>> = {
        reference_ = 0x6f97c2a8
      }, <No data fields>}, 
      verify_error_class_ = {
      <art::mirror::ObjectReference<false, art::mirror::Class>> = {
        reference_ = 0x0
      }, <No data fields>}, 
      vtable_ = {
      <art::mirror::ObjectReference<false, art::mirror::PointerArray>> = {
        reference_ = 0x6f8ce7a0
      }, <No data fields>}, 
      access_flags_ = 0x80401, 
      direct_methods_ = 0x6fbb0700, 
      ifields_ = 0x0, 
      sfields_ = 0x6fb1bf28, 
      virtual_methods_ = 0x0, 
      class_size_ = 0x90, 
      clinit_thread_id_ = 0x299, 
      dex_class_def_idx_ = 0x47c, 
      dex_type_idx_ = 0x572, 
      num_direct_methods_ = 0x2, 
      num_instance_fields_ = 0x0, 
      num_reference_instance_fields_ = 0x0, 
      num_reference_static_fields_ = 0x0, 
      num_static_fields_ = 0x1, 
      num_virtual_methods_ = 0x0, 
      object_size_ = 0x1c, 
      primitive_type_ = 0x20000, 
      reference_instance_offsets_ = 0x1f, 
      status_ = 0xa, 
      static java_lang_Class_ = {
      root_ = {
        <art::mirror::ObjectReference<false, art::mirror::Object>> = {
          reference_ = 0x6f95d1b8
        }, <No data fields>}
       }
      }
      
    • 查看Class name
      (gdb) p *('art::mirror::String' *)0x6f62c478
      $90 = {
      <art::mirror::Object> = {
      static kVTableLength = 11, 
      static hash_code_seed = {
        <std::__1::atomic<unsigned int>> = {
          <std::__1::__atomic_base<unsigned int, true>> = {
            <std::__1::__atomic_base<unsigned int, false>> = {
              __a_ = {
                __a_value = 1194485208
              }
            }, <No data fields>}, <No data fields>}, <No data fields>}, 
      klass_ = {
        <art::mirror::ObjectReference<false, art::mirror::Class>> = {
          reference_ = 1872091144
        }, <No data fields>}, 
      monitor_ = 0
      }, 
      members of art::mirror::String: 
      count_ = 29, 
      hash_code_ = 3112926936, 
      value_ = 0x6f62c488, 
      static java_lang_String_ = {
      root_ = {
        <art::mirror::ObjectReference<false, art::mirror::Object>> = {
          reference_ = 1872091144
        }, <No data fields>}
       }
      }
      
      (gdb) x /1sh 0x6f62c488
      0x6f62c488: u"java.lang.VirtualMachineError"
      
    • 几个疑点
      • 该对象实际为java.lang.VirtualMachineError类对象
      • class_size_ = 0x90 = 144,怎么会访问offset = 444的内存?
  • 对比正常Throwable对象

    • Throwable Class
      (gdb) p /x *('art::mirror::Class' *)0x6f9680d0
      $93 = {
      <art::mirror::Object> = {
      static kVTableLength = 0xb, 
      static hash_code_seed = {
        <std::__1::atomic<unsigned int>> = {
          <std::__1::__atomic_base<unsigned int, true>> = {
            <std::__1::__atomic_base<unsigned int, false>> = {
              __a_ = {
                __a_value = 0x473265d8
              }
            }, <No data fields>}, <No data fields>}, <No data fields>}, 
      klass_ = {
        <art::mirror::ObjectReference<false, art::mirror::Class>> = {
          reference_ = 0x6f95d1b8
        }, <No data fields>}, 
      monitor_ = 0x0
      }, 
      members of art::mirror::Class: 
      static kClassWalkSuper = 0xc0000000, 
      static kImtSize = 0x40, 
      class_loader_ = {
      <art::mirror::ObjectReference<false, art::mirror::ClassLoader>> = {
        reference_ = 0x0
      }, <No data fields>}, 
      component_type_ = {
      <art::mirror::ObjectReference<false, art::mirror::Class>> = {
        reference_ = 0x0
      }, <No data fields>}, 
      dex_cache_ = {
      <art::mirror::ObjectReference<false, art::mirror::DexCache>> = {
        reference_ = 0x6f8cafe0
      }, <No data fields>}, 
      dex_cache_strings_ = {
      <art::mirror::ObjectReference<false, art::mirror::ObjectArray<art::mirror::String> >> = {
        reference_ = 0x6f3ddae8
      }, <No data fields>}, 
      iftable_ = {
      <art::mirror::ObjectReference<false, art::mirror::IfTable>> = {
        reference_ = 0x6f8cbd48
      }, <No data fields>}, 
      name_ = {
      <art::mirror::ObjectReference<false, art::mirror::String>> = {
        reference_ = 0x6f6272b8
      }, <No data fields>}, 
      super_class_ = {
      <art::mirror::ObjectReference<false, art::mirror::Class>> = {
        reference_ = 0x6f95db30
      }, <No data fields>}, 
      verify_error_class_ = {
      <art::mirror::ObjectReference<false, art::mirror::Class>> = {
        reference_ = 0x0
      }, <No data fields>}, 
      vtable_ = {
      <art::mirror::ObjectReference<false, art::mirror::PointerArray>> = {
        reference_ = 0x0
      }, <No data fields>}, 
      access_flags_ = 0x80001, 
      direct_methods_ = 0x6fd39b58, 
      ifields_ = 0x6fb10ab8, 
      sfields_ = 0x6fb10aa8, 
      virtual_methods_ = 0x6fb96b98, 
      class_size_ = 0x1f0, 
      clinit_thread_id_ = 0x299, 
      dex_class_def_idx_ = 0x87, 
      dex_type_idx_ = 0x569, 
      num_direct_methods_ = 0xc, 
      num_instance_fields_ = 0x5, 
      num_reference_instance_fields_ = 0x5, 
      num_reference_static_fields_ = 0x0, 
      num_static_fields_ = 0x1, 
      num_virtual_methods_ = 0xd, 
      object_size_ = 0x1c, 
      primitive_type_ = 0x20000, 
      reference_instance_offsets_ = 0x1f, 
      status_ = 0xa, 
      static java_lang_Class_ = {
      root_ = {
        <art::mirror::ObjectReference<false, art::mirror::Object>> = {
          reference_ = 0x6f95d1b8
        }, <No data fields>}
       }
      }
      
    • 查看Class name
      (gdb) p /x *('art::mirror::String' *)0x6f6272b8
      $94 = {
      <art::mirror::Object> = {
      static kVTableLength = 0xb, 
      static hash_code_seed = {
        <std::__1::atomic<unsigned int>> = {
          <std::__1::__atomic_base<unsigned int, true>> = {
            <std::__1::__atomic_base<unsigned int, false>> = {
              __a_ = {
                __a_value = 0x473265d8
              }
            }, <No data fields>}, <No data fields>}, <No data fields>}, 
      klass_ = {
        <art::mirror::ObjectReference<false, art::mirror::Class>> = {
          reference_ = 0x6f95d808
        }, <No data fields>}, 
      monitor_ = 0x0
      }, 
      members of art::mirror::String: 
      count_ = 0x13, 
      hash_code_ = 0x612cf26c, 
      value_ = 0x6f6272c8, 
      static java_lang_String_ = {
      root_ = {
        <art::mirror::ObjectReference<false, art::mirror::Object>> = {
          reference_ = 0x6f95d808
        }, <No data fields>}
       }
      }
      
      (gdb) x /1sh 0x6f6272c8
      0x6f6272c8: u"java.lang.Throwable"
      
    • 查看method
      • class_size_ = 0x1f0 = 496
      • 虚函数表中的ArtMethod
        (gdb) x /4xw 0x6f9680d0+444
        0x6f96828c:     0x6fb96bc0      0x6fb96be8      0x6fb96c10      0x6fb96c38
        
      • 相应的跳转函数
        (gdb) x /4xw 0x6fb96bc0+36
        0x6fb96be4:     0x71dc550d      0x6f9680d0      0x6f3be5e0      0x6f3bb090
        
      • 查看offset对应method
        (gdb) p /x 0x71dc550d - 0x6fde7000 - 0x1000
        $12 = 0x1fdd50d
        
        正好对应java.lang.Throwable.fillInStackTrace()
        
        13: java.lang.Throwable java.lang.Throwable.fillInStackTrace() (dex_method_idx=13805)
          DEX CODE:
          0x0000: 5410 e426                 | iget-object v0, v1, [Ljava/lang/StackTraceElement; java.lang.Throwable.stackTrace // field@9956
          0x0002: 3900 0300                 | if-nez v0, +3
          0x0004: 1101                      | return-object v1
          0x0005: 7100 f635 0000            | invoke-static {}, java.lang.Object java.lang.Throwable.nativeFillInStackTrace() // method@13814
          0x0008: 0c00                      | move-result-object v0
          0x0009: 5b10 e326                 | iput-object v0, v1, Ljava/lang/Object; java.lang.Throwable.stackState // field@9955
          0x000b: 6200 7739                 | sget-object  v0, [Ljava/lang/StackTraceElement; libcore.util.EmptyArray.STACK_TRACE_ELEMENT // field@14711
          0x000d: 5b10 e426                 | iput-object v0, v1, [Ljava/lang/StackTraceElement; java.lang.Throwable.stackTrace // field@9956
          0x000f: 1101                      | return-object v1
        OatMethodOffsets (offset=0x019cced0)
          code_offset: 0x01fdd50d
        
  • 进一步结论

    • 类的继承关系

      public abstract class VirtualMachineError extends Error { }
      
      public class Error extends Throwable { }
      
      public class Throwable implements java.io.Serializable { }
      
    • VirtualMachineError是个抽象类,是不能实例化为对象的

    • 目前唯一实例化的地方在art虚拟机

      self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",...)
      
    • 做实验证明,当在art虚拟机抛出VirtualMachineError异常时,确实会得到类似的堆栈.

      • patch
      diff --git a/runtime/thread.cc b/runtime/thread.cc
      index 5274f9e..146068f 100644
      --- a/runtime/thread.cc
      +++ b/runtime/thread.cc
      @@ -1035,7 +1035,9 @@ struct StackDumpVisitor : public StackVisitor {
           last_method(nullptr),
           last_line_number(0),
           repetition_count(0),
      -    frame_count(0) {}
      +    frame_count(0) {
      +    thread_in->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;", "tim test");
      +   }
      
      virtual ~StackDumpVisitor() {
       if (frame_count == 0) {
      
      • 测试结果
      Revision: '0'
      ABI: 'arm'
      pid: 1374, tid: 1378, name: Signal Catcher  >>> com.android.settings <<<
      signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x5540068
          r0 05540054  r1 22cf02a0  r2 710da638  r3 ace70500
          r4 b4cfc8e0  r5 fffff7ac  r6 710da638  r7 05540054
          r8 ace70500  r9 ace70500  sl 70f4d810  fp b6d38ec0
          ip b4442eb0  sp b4442d90  lr b499651d  pc b4c976f8  cpsr 000b0030
          d0  b4d89500b6d4130c  d1  b4d89508b6d34594
          d2  b6d16627af803b48  d3  b4dac28070d1d580
          d4  bb72184fb4cc7810  d5  b49d1c5bb4d9a248
          d6  0000000000000001  d7  0000000000000001
          d8  406a51eb851eb851  d9  3fedb6db6db6db6e
          d10 3fefd70a3d70a3d7  d11 3ff0000000000000
          d12 406a51eb851eb851  d13 0000000000000000
          d14 0000000000000000  d15 0000000000000000
          d16 0000000000000003  d17 0000000000000000
          d18 408f400000000000  d19 4078900000000000
          d20 403c124924924925  d21 40db69db6db6db6e
          d22 408f400000000000  d23 406aa00000000000
          d24 410a004000000000  d25 3fc47ae147ae1480
          d26 406aa00000000000  d27 408f400000000000
          d28 4064000000000005  d29 3fedb6db6db6db6e
          d30 3fefd70a3d70a3d7  d31 3ff0000000000000
          scr 80000010
      
      backtrace:
          #00 pc 003e76f8  /system/lib/libart.so (artInvokeInterfaceTrampoline+27)
          #01 pc 000e6519  /system/lib/libart.so (art_quick_invoke_interface_trampoline+40)
          #02 pc 73209af7  /data/dalvik-cache/arm/system@framework@boot.oat (offset 0x2057000)
      
    • Google已于2016年底修复这一原生bug, patch在这里.

      这说明当前堆栈并不是第一现场,需要合入该patch正常打印出异常后才知道哪里出了问题.

  • 合入patch后,观察art正常抛出的异常

    10-23 10:49:30.301 15871 15921 E AndroidRuntime: FATAL EXCEPTION: AsyncTask #3
    10-23 10:49:30.301 15871 15921 E AndroidRuntime: Process: com.flipkart.android, PID: 15871
    10-23 10:49:30.301 15871 15921 E AndroidRuntime: java.lang.RuntimeException: An error occurred while executing doInBackground()
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at android.os.AsyncTask$3.done(AsyncTask.java:310)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at java.util.concurrent.FutureTask.run(FutureTask.java:242)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:235)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at java.lang.Thread.run(Thread.java:818)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime: Caused by: java.lang.InternalError: Invoking   Public Credential:  with bad arg 0, type 'Ljava/lang/String;' not instance of 'Ljava/io/OutputStream;'
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at com.flipkart.android.notification.c.sendFCMDataToBackend(MessagingUtils.java:87)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at com.flipkart.android.notification.c.doRegisterForFCM(MessagingUtils.java:77)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at com.flipkart.android.splash.InitHelper.b(InitHelper.java:75)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at com.flipkart.android.splash.InitHelper.init(InitHelper.java:37)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at com.flipkart.android.SplashActivity$a.doInBackground(SplashActivity.java:207)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at com.flipkart.android.SplashActivity$a.doInBackground(SplashActivity.java:191)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at android.os.AsyncTask$2.call(AsyncTask.java:296)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    10-23 10:49:30.301 15871 15921 E AndroidRuntime:        ... 4 more
    

    从异常堆栈中可看到,前面的VirtualMachineError已经变为InternalError了.

Root Cause

  • App在运行过程中遇到异常,art虚拟机抛出VirtualMachineError. 而java.lang.VirtualMachineError是抽象类,不能实例化,且其类大小只有0x90=144个bytes, 当访问offset = 444内存时,必定越界,恰巧跳转到art_quick_invoke_interface_trampoline(),再往后,libart.so相关的堆栈基本就是错的了,相当于函数已经跑飞.
  • 第三方App的异常还需要继续跟踪.

解决方案

  • ART虚拟机抛出VirtualMachineError bug在Andriod 6.0/7.0./7.1中存在, Android 8.0已修复
  • 第三方App抛异常的问题还须其它同事继续定位.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 问题现象 复现步骤手机(Android 8.0, build id为opr6.170623.013)复现场景一: ...
    dumphex阅读 14,050评论 10 4
  • 有时你想着,与人为善总是好的——凡事退一步就会海阔天空,何必斤斤计较那一点点的得失或者强势。然而事实就是会经常推翻...
    肥猫夏夏阅读 199评论 0 1
  • 业务层其实并不复杂,但是大部分开发人员对其职责并没有理解清楚,从而使其沦落为一个数据中转站。我之前分享过的Andr...
    Yiart阅读 1,261评论 0 0