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抛异常的问题还须其它同事继续定位.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,104评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,816评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,697评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,836评论 1 298
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,851评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,441评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,992评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,899评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,457评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,529评论 3 341
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,664评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,346评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,025评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,511评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,611评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,081评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,675评论 2 359

推荐阅读更多精彩内容

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