zoukankan      html  css  js  c++  java
  • Flutter Crash Analytics(iOS)

    Flutter App crash日志搜集包括三部分,一部分来自于Dart code引起的异常,可以在flutter framework的main函数进行全局捕获,此外还需对Native端iOSAndroid的异常进行捕获.

    iOS异常搜集与分析

    • 开启DWARF文件搜集

    • 获取Mach异常和Unix信号(),用于捕获系统内核的异常,在http://opensource.apple.com 可以看到内核的完整代码;

      void InstallUncaughtExceptionHandler()
      {
      //根据需要选择性的配置
      signal(SIGABRT, CustomSignalHandler);
      signal(SIGILL, CustomSignalHandler);
      signal(SIGSEGV, CustomSignalHandler);
      signal(SIGFPE, CustomSignalHandler);
      signal(SIGBUS, CustomSignalHandler);
      signal(SIGPIPE, CustomSignalHandler);
      ...
      }
    • 注册NSSetUncaughtExceptionHandler捕获应用异常事件

    • 通过三方库搜集,KSCrash,plcrashreporter,CrashKit,Crashlytics,Hockeyapp,友盟,Bugly,App Dynamic

    • 获取Crash符号日志

      • 通过手机链接上Xcode直接获取
      • 通过应用内置的异常获框架获取crash日志并上传到服务器.

    Crash日志解析

    • 隐藏符号替换: 根据官方文档的说明通过AppStore发布之后下载的dysm文件会有部分敏感符号被隐藏,本地生成的则不会替换。所以在使用时需要先将其替换

        dsymutil -symbol-map <PathToXcodeArchive>/MyGreatApp.xcarchive/BCSymbolMaps <PathToDownloadedDSYMs>/<UUID>.dSYM
      
    • 检测Crash日志的uuid和ipa的执行文件uuid是否相同

      dwarfdump --uuid <PathToDSYMFile>/Contents/Resources/DWARF/<BinaryName>
      dwarfdump --uuid <PathToBinary>
      
    • 当crash日志和对应的ipa执行文件uuid对应之后,利用xcode的Symbolicate工具进行符号化,注意这里的-l后面的参数,分别指定了

      atos -arch <BinaryArchitecture> -o <PathToDSYMFile>/Contents/Resources/DWARF/<BinaryName>  -l <LoadAddress> <AddressesToSymbolicate>
      atos -arch arm64 -o TouchCanvas.app.dSYM/Contents/Resources/DWARF/TouchCanvas -l 0x1022c0000 0x00000001022df754
      ViewController.touchesEstimatedPropertiesUpdated(_:) (in TouchCanvas) + 304
    • 使用内置的工具解析

      export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer​
      ./symbolicatecrash /Users/yourUserName/Desktop/CrashSignifying/crashFileName.crash /Users/UserName/Desktop/CrashSignifying/dSYMFileName.dSYM > crashFileName.crash
      

    Crash日志介绍,

    • 一份crash日志包含了以下几个部分

    • Header:

      Incident Identifier: 6156848E-344E-4D9E-84E0-87AFD0D0AE7B
      CrashReporter Key:   76f2fb60060d6a7f814973377cbdc866fffd521f
      Hardware Model: iPhone8,1
      Process: TouchCanvas [1052]
      Path: /private/var/containers/Bundle/Application/51346174-37EF-4F60-B72D-8DE5F01035F5/TouchCanvas.app/TouchCanvas
      Identifier: com.example.apple-samplecode.TouchCanvas
      Version: 1 (3.0)
      Code Type: ARM-64 (Native)
      Role: Foreground
      Parent Process: launchd [1]
      Coalition: com.example.apple-samplecode.TouchCanvas [1806]
      Date/Time: 2020-03-27 18:06:51.4969 -0700
      Launch Time: 2020-03-27 18:06:31.7593 -0700
      OS Version: iPhone OS 13.3.1 (17D50)
    • Exception Information:

      Exception Type:  EXC_BREAKPOINT (SIGTRAP) 异常类型
      Exception Subtype: 异常类型可读取的描述信息
      Exception Message: 对Exception Type的解释
      Exception Codes: 0x0000000000000001, 0x0000000102afb3d0 一个64bit的异常code
      Exception Note:
      不属于一个特定的异常类型。如果此字段包含EXC_corpost_NOTIFY,则崩溃并非源自硬件陷阱,原因可能是该进程已被操作系统或名为abort()的进程显式终止。如果此字段包含SIMULATED(这不是崩溃),则进程没有崩溃,但操作系统可能随后请求终止进程。如果此字段包含非致命条件(这不是崩溃),则进程不会终止,因为创建崩溃报告的问题不是致命的。
      Termination Reason: 应用程序终止的具体原因
      Triggered by Thread or Crashed Thread: 触发崩溃或者崩溃的线程
    • Diagnostic Messages: 系统当前对app的诊断信息

      Termination Description: SPRINGBOARD, 
      scene-create watchdog transgression: application<com.example.MyCoolApp>:667
      exhausted real (wall clock) time allowance of 19.97 seconds

    常见的异常处理方案

    1. WatchDog timeout: 这种异常通常是由于主线程阻塞造成,同步的网络请求,处理大量的model转换,如json解析,3d models的解析,同步的处理大量的coredata数据,应用计算机视觉算法对输入图像和视频执行各种任务。

      • 下面2张图时是改善前后的方案

      • 改进之后

      • scence-create超时

         Termination Description: SPRINGBOARD, 
        scene-create watchdog transgression: application<com.example.MyCoolApp>:667
        exhausted real (wall clock) time allowance of 19.97 seconds
        | ProcessVisibility: Foreground
        | ProcessState: Running
        | WatchdogEvent: scene-create
        | WatchdogVisibility: Foreground
        | WatchdogCPUStatistics: (
        | "Elapsed total CPU time (seconds): 15.290 (user 15.290, system 0.000), 28% CPU",
        | "Elapsed application CPU time (seconds): 0.367, 1% CPU"
        | )
      • 后台任务执行超时

        Termination Reason: CAROUSEL, WatchConnectivity watchdog transgression. 
        Exhausted wall time allowance of 15.00 seconds.
        Termination Description: SPRINGBOARD,
        CSLHandleBackgroundWCSessionAction watchdog transgression: xpcservice<com.example.MyCoolApp.watchkitapp.watchextension>:220:220
        exhausted real (wall clock) time allowance of 15.00 seconds
        | <FBExtensionProcess: 0x16df02a0; xpcservice<com.example.MyCoolApp.watchkitapp.watchextension>:220:220; typeID: com.apple.watchkit>
        Elapsed total CPU time (seconds): 24.040 (user 24.040, system 0.000), 81% CPU
        | Elapsed application CPU time (seconds): 1.223, 6% CPU, lastUpdate 2020-01-20 11:56:01 +0000
    2. Memory Access Crash: 内存访问crash

      • 取消引用指向无效的地址空间,往只读的空间写入数据,访问无效地址的指令,通常会出现EXC_BAD_ACCESS(SIGSEGV),或者是EXC_BAD_ACCESS(SIGBUS)异常
        text
        Exception Type: EXC_BAD_ACCESS (SIGSEGV)
        Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000
      • 坏的内存访问有时候不会生成EXC_BAD_ACCESS,直接抛出一个signal异常,例如:SIGSEGV, SEGV_MAPERR, or SEGV_NOOP text Exception Type: SIGSEGV
        Exception Codes: SEGV_MAPERR at 0x41e0af0c5ab8
      • 内存访问异常分析

        • Address Sanitizer(gcc ... -fsanitize=address): 内存错误检查,在Xcode运行面板中可以开启此项检查。
          • 比如使用一个释放的对象
          • 数组越界,栈缓存溢出
        • Undefined Behavior Sanitizer: 不安全的操作指令
          • 缓冲区溢出
          • 使用未初始化的变量
          • 使用释放后的变量
          • 重复释放
          • 多线程数据竞争
        • Thread Sanitizer: 线程安全检查
          • 记录内存访问信息,判断是否有不同线程访问修改其值
        • Profile Analytics: 静态分析检查
          • 在运行时检查,未初始化变量,泄漏,未使用变量
        • Enabling the Malloc Debugging Features: 开启僵尸检查模式,可以给释放的对象发送消息,来检测异常
      • 异常子类型检查

         Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
         Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000
        ...
        Exception Type: EXC_BAD_ACCESS (SIGBUS)
        Exception Codes: KERN_MEMORY_ERROR at 0x00000001098c1000
        KERN_INVALID_ADDRESS: 无效的内存地址
        KERN_PROTECTION_FAILURE: 使用受保护的地址空间,不属于当前线程的空间
        KERN_MEMORY_ERROR: 访问的地址无法提供数据,如分页缺失
        EXC_ARM_DA_ALIGN: 访问的内存地址未对齐
      • 虚拟内存引用错误,应用了其它的app的vm region

        Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
        Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000
        VM Region Info: 0 is not in any region. Bytes before following region: 4307009536
        REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL
        UNUSED SPACE AT START
        --->
        __TEXT 0000000100b7c000-0000000100b84000 [ 32K] r-x/r-x SM=COW ...pp/MyGreatApp
        • 如果objc_msgSend, objc_retain, or objc_release在堆栈信息的最上方,考虑开启Zombie Objects检查 .
        • 如果gpus_ReturnNotPermittedKillClient出现,则说明试图在后台使用OpenGL ES进行渲染,需要将OpenGL ES代码移植到Metal,移植参考Migrating OpenGL Code to Metal.
    3. EXC_BREAKPOINT

      • EXC_BREAKPOINT (SIGTRAP) and EXC_BAD_INSTRUCTION (SIGILL): 跟中陷阱终断,或者不合法的指令(illegal), 模拟 __builtin_trap
    4. EXC_CRASH (SIGABRT): 程序执行了abort()函数,如算数逻辑错误保护,程序启动的必选参数强制保护.扩展初始化占用时间过长被系统执行了abort()

    5. EXC_CRASH (SIGKILL): kill,

      • 0x8badf00d(bad food,watch dog issue);
      • 0xc00010ff(cool off),系统由于热事件终止应用程序, 运行环境异常,电量使用过大造成,可以参考iOS Performance and Power Optimization with Instruments;
      • 0xbaadca11(bad call),操作系统终止了应用程序,因为未能报告对PushKit通知的CallKit调用。
      • 0xbad22222,系统终止了VoIP应用程序,因为它恢复得太频繁,(提示,2重复了很多次);
      • 0xc51bad01(backgroud),watchOS终止了应用程序,因为它在执行后台任务时占用了太多的CPU时间。(自身的问题)
      • 0xc51bad02(backgroud), watchOS终止了应用程序,因为它未能在分配的时间内完成后台任务。(自身的问题)
      • 0xc51bad03(backgroud), watchOS终止了应用程序,因为它未能在分配的时间内完成后台任务,但系统总体上非常繁忙,应用程序可能没有收到太多CPU时间来执行后台任务。(系统的问题)
      • EXC_CRASH (SIGQUIT): 进程在另一个进程的请求下终止(具备管理这个进程的生命周期)。
      • EXC_GUARD: 违反了保护资源的原则。,但大多数受保护的资源崩溃都来自受保护的文件描述符,这些描述符在异常子类型字段中具有GUARD_TYPE_FD(guard type file descriptor)值。操作系统将文件描述符标记为受保护的,这样普通的文件描述符API就无法修改它们, CLOSE,DUP(duplicate),NOCLOEXEC,SOCKET_IPC,FILEPORT,WRITE
      • EXC_RESOURCE: 进程超出了资源消耗限制。CPU and CPU_FATAL,MEMORY,IO(disk task),WAKEUPS(每秒醒来次数太多,这会消耗电池寿命), such as perform(_:on:with:waitUntilDone:), async(execute:), or dispatch_async(_:_:),执行过于频繁,GCD负荷过重,参考Modernizing Grand Central Dispatch Usage, 队列控制,计划执行,并发数控制
      • EXC_ARITHMETIC: 逻辑运算错误,除0或浮点运算错误
    6. App内存不足被强制杀掉: 虚拟内存占用过高导致被杀掉

      • app在启动后以pageFault的方式,将物理空间上的内存以分页的形式映射到内存中
      • crash demo: 通常它不会作为crash日志搜集,在系统设置统计分析中可以找到这些日志.
        text
        "crashReporterKey" : "b9aa251a63bd9e743afbb906f43eb7ea5f206292",
        "product" : "iPad8,2",
        "incident" : "32B05E3C-CB45-40F8-BA66-5668779740E1",
        "date" : "2019-10-10 23:30:39.48 -0700",
        "build" : "iPhone OS 13.1.2 (17A860)",
        "memoryStatus" : {
        "pageSize" : 16384,
        },
        "largestProcess" : "OneCoolApp", //占用内存最大进程,因某种原因被系统杀掉

      • 特别注意: 一个jetsam event报告包括一个数组进程,如果你的app崩溃了,但是被挂掉的进程不是你的app,就需通过其它的诊断途径来查看问题,确认手机内是否有其它的crash日志
      • reason: per-process-limit,进程超过了系统限定的程序内存驻留最大限制,超过此大小,将极大可能被系统杀掉,应用程序的扩展进程也被考虑在内,并且他们的内存占用限制更少
        text
        {
        "uuid" : "a02fb850-9725-4051-817a-8a5dc0950872",
        "states" : [
        "frontmost"
        ],
        "lifetimeMax" : 92802,
        "purgeable" : 0,
        "coalition" : 68,
        "rpages" : 92802,
        "reason" : "per-process-limit",
        "name" : "MyCoolApp"
        }
        • reason: vm-pageshortage,系统内存压力过重,杀掉后台应用
        • reason: vnode-limit,系统打开了太多的文件,内核有限制vnode数量,会放弃部分后台进程,保证前台应用存活
        • reason: highwater,系统守护进程超出了最高内存占用
        • reason: fc-thrashing, 当内存映射文件的非连续部分读写过于频繁时,就会发生这种情况。为了避免终止最前端的应用程序,系统可能会在后台终止您的应用程序,以释放文件缓存中的空间,即使您的应用程序没有破坏文件缓存。
        • reason: jettisoned,系统杀掉了应用程序因为一些其它的原因
        • pageSize默认为16KB
        • pageSize优化: 方法重排,常用方法集中到一个页,避免频繁切换,合理利用数据结构,减少不必要的开销,字节对齐,进一步优化数据占用空间,
        • 可以通过vm_stat查看进程的vm空间 text Mach Virtual Memory Statistics: (page size of 4096 bytes)
          Pages free: 3194.
          Pages active: 34594.
          Pages inactive: 17870.
          Pages wired down: 9878.
          "Translation faults": 6333197.
          Pages copy-on-write: 81385.
          Pages zero filled: 3180051.
          Pages reactivated: 343961.
          Pageins: 33043.
          Pageouts: 78496.
          Object cache: 66227 hits of 96952 lookups (68% hit rate)
    7. Diagnosing Memory, Thread, and Crash Issues Early

      UBSan check Compiler flag
      Misaligned Pointer -fsanitize=alignment
      Invalid Boolean -fsanitize=bool
      Out-of-Bounds Array Access -fsanitize=bounds
      Invalid Enumeration Value -fsanitize=enum
      Dynamic Type Violation -fsanitize=vptr
      Invalid Float Cast -fsanitize=float-cast-overflow
      Division by Zero -fsanitize=integer-divide-by-zero,-fsanitize=float-divide-by-zero
      Nonnull Argument Violation -fsanitize=nonnull-attribute, -fsanitize=nullability-arg
      Nonnull Return Value Violation -fsanitize=returns-nonnull-attribute, -fsanitize-nullability-return
      Nonnull Variable Assignment Violation -fsanitize=nullability-assign
      Null Reference Creation and Null Pointer Dereference -fsanitize=null
      Invalid Object Size -fsanitize=object-size
      Invalid Shift -fsanitize=shift
      Integer Overflow -fsanitize=signed-integer-overflow
      Reaching of Unreachable Point -fsanitize=unreachable
      Invalid Variable-Length Array -fsanitize=vla-bound

    参考地址

    Understanding the Exception Types in a Crash Report
    iOS Performance and Power Optimization with Instruments
    Adding Identifiable Symbol Names to a Crash Report
    Diagnosing Memory, Thread, and Crash Issues Early
    Improving Your App's Performance
    Examining the Fields in a Crash Report
    Viewing Virtual Memory Usage
    Writing ARM64 Code for Apple Platforms
    Investigating Memory Access Crashes
    Apple官方文档WatchDog处理方案
    Identifying High-Memory Use with Jetsam Event Reports

  • 相关阅读:
    单元测试
    英语学习app案列分析
    基于GUI的四则运算
    个人作业1——四则运算题目生成程序(基于控制台)
    一种新体验———构建之法
    个人作业3——个人总结(Alpha阶段)
    单元测试
    英语学习APP案例分析
    结对编程(70,73)
    软件工程HW1-四则运算软件
  • 原文地址:https://www.cnblogs.com/wwoo/p/flutter-crash-analyticsios.html
Copyright © 2011-2022 走看看