一种程序崩溃信息的收集方法及系统
技术领域
本发明涉及计算机应用技术领域,具体涉及一种程序崩溃信息的收集方法及系统。
背景技术
Android(安卓)是一种基于Linux的自由及开放源代码的操作系统,主要用在移动设备上,如智能手机、平板电脑等。安卓系统由于其良好的开源特性,使得从事安卓应用程序开发的人员越来越多,进而也促使市面上出现了多版本的安卓系统和应用程序。众多的版本造成了系统的兼容性变差,使安卓系统的碎片化严重,常常出现应用程序崩溃的现象,有些严重的崩溃问题还发生在软件产品发布以后,使得用户体验变差。通过崩溃捕获和收集,可以收集到已发布应用的异常,以便开发人员发现和修改,这对于提高软件质量有着极大的帮助,因此,崩溃信息的收集变得非常重要。
目前,常见的安卓系统崩溃有两类,一类是Java Exception异常,一类是NativeSignal异常。现有技术中,能够对Java层的崩溃日志进行收集,但该部分信息还不足以分析出崩溃原因。目前对于Native层的崩溃信息的收集目前还没有很好的方法,只能通过logcat日志查看相关的堆栈信息,而logcat日志只起记录的作用,并不能在发生崩溃时通知系统,换句话说,在Native层发生崩溃时,除非程序员主动查看logcat日志,否则是不能知晓Native层是否已经崩溃及崩溃原因的。
发明内容
为解决现有技术中不能对Native层崩溃信息进行全面收集的缺陷,本发明提供一种程序崩溃信息的收集方法,包括:
对各应用服务分别加载监听接口,并对所述监听接口进行初始化;所述监听接口用于监听Native层是否发生崩溃;
当所述监听接口监听到Native层崩溃时,收集崩溃信息,具体包括:
收集Native层的崩溃日志;
执行Shell命令,通知Java层出现Native崩溃;
收集Native崩溃时的系统关键信息;
将收集到的所述崩溃信息存入指定路径,并上传至服务器。
其中,所述系统关键信息包括崩溃时的内存运行数据、抓取的logcat日志、运行设备的信息、进程信息和应用程序基本信息。
其中,还包括在所述收集崩溃信息以后,杀掉当前崩溃的进程。
其中,所述初始化包括指定存储所述崩溃信息的路径及初始化Shell命令。
本发明还提供一种程序崩溃信息的收集系统,包括:
监听模块,用于对各应用服务分别加载监听接口,并对所述监听接口进行初始化,所述监听接口用于监听Native层是否发生崩溃;
崩溃信息收集模块,用于在所述监听接口监听到Native层崩溃时,收集崩溃信息,具体包括:
崩溃日志收集子模块,用于收集Native层的崩溃日志;
通知子模块,用于执行Shell命令,通知Java层出现Native崩溃;
系统关键信息收集子模块,用于收集Native崩溃时的系统关键信息;
上传模块,用于将收集到的所述崩溃信息存入指定路径,并上传至服务器。
其中,所述系统关键信息包括崩溃时的内存运行数据、抓取的logcat日志、运行设备的信息、进程信息和应用程序基本信息。
其中,还包括删除模块,用于在所述崩溃信息收集模块收集崩溃信息以后,杀掉当前崩溃的进程。
其中,还包括初始化模块,具体用于指定存储所述崩溃信息的路径及初始化Shell命令。
本发明提供的一种程序崩溃信息的收集方法,通过在各应用服务中分别加载监听接口,并对监听接口进行初始化,可实时监听Native层是否发生了崩溃,使得在发生程序崩溃时,能及时将进程跳转至崩溃信息收集进程,并收集崩溃信息,方便程序开发人员找到程序崩溃的原因并解决崩溃问题。在崩溃信息收集过程中,首先对Native层的崩溃日志进行了收集,使得程序开发人员能及时获知发生Native崩溃的具体位置;通过执行Shell命令,通知Java层出现了Native崩溃,进而对崩溃时的系统关键信息进行了收集,使得收集到的崩溃信息更全面,方便程序开发者更及时、准确地解决崩溃问题。另外,本发明提供的一种程序崩溃信息的收集系统,通过设置监听模块并将其加载至应用服务,实现了监听Native层是否发生崩溃的目的,通过设置的崩溃信息收集模块,实现了Native层的崩溃日志及系统关键信息的全面收集,并通过上传模块将收集到的崩溃信息上传至服务器,使得程序开发人员能随时查看崩溃信息,及时对系统崩溃做出应对。
附图说明
图1为本发明中程序崩溃信息的收集方法的流程图;
图2为本发明中程序崩溃信息的收集系统的示意图;
图3为本发明中崩溃信息收集模块示意图;
其中,1、监听模块;2、崩溃信息收集模块;3、上传模块;21、崩溃日志收集子模块;22、通知子模块;23、系统关键信息收集子模块。
具体实施方式
为使本发明实施例的目的、技术方案和优点更加清楚,下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚地描述,显然,所描述的实施例是本发明一部分实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都属于本发明保护的范围。
图1为本发明中程序崩溃信息的收集方法的流程图;图2为本发明中程序崩溃信息的收集系统的示意图。
Android系统是一种自由及开放源代码的操作系统,基于Linux内核实现。Android系统使用Java语言进行开发,而Java无法直接访问到操作系统底层,如系统硬件等,为此Java使用Native代码来扩展Java程序的功能。由于Android的碎片化造成应用程序崩溃严重,会出现Java层和Native层崩溃。Android在发生Java崩溃时,通常通过Java的UncaughtException Handler(未捕获的异常处理程序)来进行处理。但是Native代码只能开发so库(动态链接库),然后Java通过JNI(Java Native Interface,Java本地接口)来调用so库,如果Native出现了uncaught exception(未捕获异常),引起so库崩溃,即发生Native崩溃,此时是无法通过Java的Uncaught Exception Handler来处理的。熟悉Linux开发的人都知道,so库一般通过gcc/g++进行编译,崩溃时会产生信号异常。Android底层是Linux系统,所以so库崩溃时也会产生信号异常。那么如果我们能够捕获信号异常,就相当于捕获了Native崩溃信息。实施例1:
如图1所示,本实施例提供一种程序崩溃信息的收集方法,用于收集Native崩溃信息,包括以下步骤:
对各应用服务分别加载监听接口,并对所述监听接口进行初始化;监听接口用于监听Native层是否发生崩溃。
具体地,首先对各应用服务分别加载监听接口。监听接口通常通过监听器实现,监听器是一个实现特定接口的普通Java程序,监听器用于监听另一个Java对象的方法调用或属性改变。每个监听接口内部包含了若干处理上述事件的抽象方法。通常每个应用服务都有一个监听接口与之相对应,每个接口还可以定义一个或多个方法。当特定的事件发生时,就会调用这些方法。例如当被监听对象发生方法调用或属性改变事件后,设定在监听接口中的特定方法将立即被执行。本发明中的监听接口用于监听Native层是否发生了崩溃。Linux存在一种信号机制,信号机制是Linux进程间通信的一种重要的方式,Linux信号一方面用于正常的任务调度和进程间通信。另一方面还负责监控系统的异常和中断,当系统发生异常时,Linux内核将产生异常信息并且通知当前进程。监听程序收到了Linux内核发出的异常信息通知,即知道Native层发生了崩溃。
例如有如下C代码:
int*p=0;
*p=1;
当执行到第二行代码的时候,程序会发生崩溃。这里定义的指针p是一个空指针,给空指针赋值是不可以的,会导致Native发生异常,进而崩溃。监听接口即用于捕获该异常情况。
当执行到*p=1;时,系统发生异常,内核会发出一个异常信号给当前的进程,监听程序通过捕获该异常信号,即可知道当前进程出现了异常。
加载监听接口时,程序开发人员只需要引入崩溃收集的SDK(SoftwareDevelopment Kit,软件开发工具包),并且在Android程序进程启动的时候,调用SDK的初始化API(Application Programming Interface,应用程序编程接口)。SDK提供了一个接口,允许用户传递自己配置的handler给SDK。当执行Uncaught Exception的时候,SDK只负责采集崩溃信息,之后便调用用户的handler来处理崩溃。
在进程启动的时候,需要对监听接口进行初始化,在安卓程序中,一般是在Application里执行初始化工作的。初始化是把变量赋为默认值,把控件设为默认状态,初始化有助于减少出现bugs的可能性。因为Native层主要是通过c/c++实现,不能直接启动和调用安卓的一些系统组件,因此需要通过调用命令来对这些系统组件进行调用,通常通过Shell指令实现,即可达到直接调用安卓系统组件的目的。Shell指令其实是处于底层的Native与处于Java层的Java进行交互的一个工具。Shell是一个命令语言解释器,它拥有自己内建的Shell命令集,同时也能被系统中其他应用程序所调用。用户在提示符下输入的命令都由Shell先解释然后传给Linux内核。Shell的一个重要功能是提供个性化的应用环境,这通常在Shell的初始化档案中完成。当Native层发生崩溃时,监听程序及时发现异常,执行Shell命令,这样就能通知Java层,此时的Native层发生了崩溃,使开发人员能进行相应的处理。因此初始化接听接口时,需要对Shell命令进行初始化。
启动进程后,监听接口启动,开始对进程运行情况进行监控。当监听接口监听到Native层崩溃时,开始进行崩溃信息收集,未监听到异常情况时,持续对启动后的进程进行监控。对崩溃信息的收集过程包括:
收集Native层的崩溃日志;
执行Shell命令,通知Java层出现Native崩溃;
收集Native崩溃时的系统关键信息。
具体地,监听到程序发生崩溃时,收集Native层的崩溃日志,并将收集到的崩溃日志存入指定的路径。缺省情况下,收集到的崩溃日志会存储在工作目录下。但是由于开始时进行了初始化设置,则崩溃日志的存储位置可以根据程序员的设定更改。崩溃日志用于记录应用程序崩溃时的信息,通常包含每个执行线程的栈调用信息。崩溃发生后,通过获取Native层代码的调用堆栈信息,即可知道崩溃发生的具体位置。崩溃日志是开发者定位和分析崩溃原因最为关键的信息。
执行Shell命令,通知Java层出现Native崩溃。利用初始化时传至Native层的Shell指令,实现系统调用,通知Java层发生了Native崩溃。Shell命令可以解析用户提交的命令行,然后按照环境变量搜索目录系统,进而执行命令。Android系统提供了adb Shell,可以处理特定的一些Shell命令,例如要启动一个系统服务,我们可以通过命令启动Android中的Activity,Service等组件。运行am startservice–n,此处n表示包名或组件名,通过这样一个指令就可以把指定包名下的一个服务唤醒,另外还可以给他传递参数,系统服务会收到。通过这个机制,Native层可以实现对Java层系统组件的调用,Java层与Native层实现交互,就可以收到Native层传递过来的消息,进而获知Native层是否发生崩溃。通过扩展Shell指令,把崩溃信息收集路径加入到Shell指令的参数集合中去,然后通过系统调用System接口,执行Shell命令,启动一个Service组件,即可进行其他信息的获取。系统调用主要供用户编程使用,也可被内核态线程调用。System_call()是系统调用的唯一入口点。Linux内核会为每一个系统调用编一个序号,称为系统调用号,通过选择调用号实现不同组件的调用。因此,Shell指令可实现不同的调用程序。
收集Native崩溃时的系统关键信息,将收集到的系统关键信息写入文件并存入指定路径。产生Native崩溃的原因有多种,例如硬件发生异常、非法内存访问、内存崩溃,或进程调用的库发现错误,给自己发送了中止信号使得进程终止等,即造成Native崩溃的原因是多样的。系统关键信息指那些程序运行过程中参与、涉及到的有用的软硬件信息,如记录了崩溃发生过程的logcat日志,正在使用的终端设备的信息、正在运行的其他进程的信息,以及发生崩溃的应用程序的基本信息等。收集这类信息,能帮助程序开发人员全面了解发生Native崩溃的具体原因。收集到的这些系统关键信息存储到初始化过程中指定的路径中。
在崩溃信息收集完成后,要将所有信息进行打包,装入一个压缩包中,然后上传至特定服务器,如日志服务器。由于不同的信息会有不同的存储路径,因此在上传服务器之前需要进行信息的打包和命名,上传方式主要为通过e-mail发送和通过HTTP(Hyper TextTransfer Protocol,超文本传输协议)发送,以及后台CGI(Common Gateway Interface,公共网关接口)发送,或者可以选择发送到Google Form等。崩溃信息上传到服务器后,可以让后台对崩溃信息进行处理,例如,对崩溃日志进行去重和崩溃统计等。上传到后台也方便开发者查阅。
本发明提供的一种程序崩溃信息的收集方法,通过在各应用服务中分别加载监听接口,并对监听接口进行初始化,可实时监听Native层是否发生了崩溃,使得在发生程序崩溃时,能及时将进程跳转至崩溃信息收集进程,并收集崩溃信息,方便程序开发人员找到程序崩溃的原因并解决崩溃问题。在崩溃信息收集过程中,首先对Native层的崩溃日志进行了收集,使得程序开发人员能及时获知发生Native崩溃的具体位置;通过执行Shell命令,通知Java层出现了Native崩溃,进而对崩溃时的系统关键信息进行了收集,使得收集到的崩溃信息更全面,方便程序开发者更及时、准确地解决崩溃问题。
在上述实施例的基础上,所述系统关键信息包括崩溃时的内存运行数据、抓取的logcat日志、运行设备的信息、进程信息和应用程序基本信息。
具体地,系统内存运行数据可能是造成Native崩溃的原因之一。例如出现非法内存访问、无法访问内存或内存空间不足的现象,都会造成程序崩溃。因此,记录下崩溃当时的内存使用情况,会为后续的崩溃原因查找提供帮助。
在本地调试代码时,程序员通常通过查看logcat日志来分析出现崩溃问题的原因。logcat是Android中一个命令行工具,可以用于得到程序的log信息。Android日志系统提供了记录和查看系统调试信息的功能。日志都是从各种软件和一些系统的缓冲区中记录下来的,缓冲区可以通过logcat命令来查看和使用。当Native崩溃时,Android系统同样会输出崩溃堆栈信息到logcat日志中,对于程序员来说,拿到了logcat日志,也就拿到了Native的崩溃堆栈信息。程序异常退出时,logcat会打印相关日志记录,但是由于安卓生成的日志太多,早期生成的日志容易被后续的日志覆盖掉,导致需要某个日志时,该日志可能已经不存在,这些日志往往可以有效地了解问题发生时的上下文,因此,要抓取发生崩溃时的logcat日志,这样可以有效帮助开发者分析问题是如何发生的,以及为什么发生。例如可以对崩溃前后1000行日志进行抓取记录,因为logcat日志记录的信息很多,不仅仅包含崩溃时的信息,如果全部获取,会给程序开发人员寻找崩溃原因带来干扰,不能快速找到问题所在,因此只需要抓取崩溃前后一定行数的日志进行记录即可。
获取运行设备的信息。由于Android系统的碎片化严重,很多崩溃只是在特定的系统或者手机上会崩溃,所以记录下崩溃的终端设备的信息是很有必要的。如果是此类问题引发的崩溃,开发者就可以根据这些信息,找到对应的终端设备进行针对性修复。
记录进程信息,可以判断出发生崩溃是否是由其他程序干扰导致的。例如有时候,进程中会混入木马程序,导致程序异常运行,通过将进程信息记录在文件中并存入指定的路径,能分析出崩溃是否是由于其他程序干扰造成的。
记录应用程序基本信息,如通过Android系统API获取当前崩溃进程包名,版本号。Android系统中,通常使用包名作为应用的唯一标识。包名必须唯一,一个包名代表一个应用,不允许两个应用使用同样的包名。包名主要用于系统识别应用,几乎不会被最终用户看到。如果出线了相同的包名,便会发生冲突,进而导致应用程序崩溃。应用发布后,包名不能随意修改,一旦修改了包名,就会被当作一个新的应用,旧版用户也无法收到相应的升级提醒。因此,记录下进程包名能为后续的问题分析提供参考。版本号是版本的标识号。每一个操作系统或者说每一个软件都有一个版本号。版本号能使程序开发人员了解所使用的操作系统是否为最新的版本以及它所提供的功能与设施。记录版本号能帮助程序开发人员分析是否是版本不兼容引发的崩溃。
通过记录上述系统关键信息,可以获得更全面的信息,用来进行奔溃分析,有利于帮助程序开发人员尽早找到发生崩溃的原因以及解决办法。
在上述实施例的基础上,还包括在收集崩溃信息以后,杀掉当前崩溃的进程。有些应用程序退出UI(User Interface用户界面)后,会在后台继续运行,而继续运行错误的进程,会占用大量的内存资源,影响其他进程的运行,因此,可以通过Linux内核中用于杀死进程的kill命令来杀掉进程,kill命令可根据进程号杀死进程。因为此时的进程已经处于异常状态,杀掉或杀掉后重启是最理想的处理方式。
在上述实施例的基础上,对监听接口的初始化包括指定存储崩溃信息的路径和初始化Shell命令。
具体地,在进程启动的时候,需要进行初始化才能完成崩溃收集。初始化时,需要指定崩溃时崩溃日志和系统关键信息的收集路径,这里只需要传入一个合法的路径即可,崩溃监听程序会记下当前路径,崩溃发生时,会把相应的信息存入用户指定的路径中去。崩溃信息包括崩溃日志和系统关键信息,其中系统关键信息又包含多种信息,因此,在指定存储路径时,可以将所有的崩溃信息存储在同一路径中,也可以分别存储在不同的路径中。存储的路径的选择主要考虑信息收集和查找的便利性。例如,程序开发者可以自定义一个本地文件夹,将需要保存的信息都存入该文件夹,或者进行分类存储,在崩溃信息收集完成后,即可迅速找到信息存储的位置,然后将收集到的信息打包上传即可。指定存储路径有利于帮助开发者快速拿到崩溃信息。
此外,还需要对Shell命令进行初始化。Shell命令主要是为了通知Java层及时收集各类信息,初始化Shell命令时会指定如下内容:1、需要通知的Android service组件;2、当前进程名和包名;3、崩溃时,把崩溃日志的路径通过参数的方式传递给Java层。通过对Shell命令进行初始化,可以明确该Shell命令用于对哪一个程序进行监控,以及该程序发生崩溃时,崩溃信息将会存储在什么位置。通过初始化时指定的崩溃信息的路径,开发者能方便地收集崩溃信息;通过对Shell命令进行初始化,能实现在发生崩溃时,及时准确地通知Java层发生崩溃的进程位置等信息。
实施例2:
本实施例提供一种与实施例1中收集方法对应的收集系统,因此在本实施例中,与实施例1相同的内容在此不再赘述。
如图2和图3所示,本实施例提供一种程序崩溃信息的收集系统,包括:
监听模块1,用于对各应用服务分别加载监听接口,并对监听接口进行初始化,监听接口用于监听Native层是否发生崩溃。
监听模块中包含多个监听接口,通常每个应用服务配置一个监听接口。当崩溃发生时,设定在监听接口中的相应程序立即被执行,起到通知Java层下层发生了崩溃的作用。启动程序前需对监听接口进行初始化。
崩溃信息收集模块2,用于在所述监听接口监听到Native层崩溃时,收集崩溃信息。崩溃信息收集模块2包括以下几个子模块:
崩溃日志收集子模块21,用于收集Native层的崩溃日志,崩溃日志记录了发生崩溃时的主要信息,程序开发人员通过对崩溃日志的分析,能找到崩溃发生的原因。崩溃日志收集到的崩溃信息可能出现重复的信息,因此还需要一个去重的过程。Android系统中,通常通过Java的Uncaught Exception Handler来进行崩溃日志的捕获,信息记录在文件后,存入初始化过程中指定的路径。崩溃日志是程序开发者进行崩溃原因分析的最重要信息。
通知子模块22,用于执行Shell命令,通知Java层出现Native崩溃。此处的Shell命令是用于通知Java层出现了Native崩溃的命令,Shell命令是一种脚本命名,通过Shell语言实现。发生崩溃时,系统调用该Shell命令,即可通知Java层出现了Native崩溃。
系统关键信息收集子模块23,用于收集Native崩溃时的系统关键信息。系统关键信息只程序运行过程中相关的信息。收集到的系统关键信息写入文件后会存入初始化过程中指定的路径。造成Native崩溃的原因多种多样,收集系统关键信息能辅助程序开发者进行崩溃原因的分析。系统关键信息的存储路径可以与崩溃日志的存储路径相同,也可以另外设置。
上传模块3,用于将收集到的崩溃信息,包括崩溃日志和系统关键信息,打包后上传至特定的服务器,例如日志服务器。将崩溃信息上传是为了日后可以方便查找资料,还可将资料永久保存。上传可通过邮箱等方式实现。
本发明提供的一种程序崩溃信息的收集系统,通过设置监听模块并将其加载至应用服务,实现了监听Native层是否发生崩溃的目的,通过设置的崩溃信息收集模块,实现了Native层的崩溃日志及系统关键信息的全面收集,并通过上传模块将收集到的崩溃信息上传至服务器,使得程序开发人员能随时查看崩溃信息,及时对系统崩溃做出应对。
在上述实施例的基础上,系统关键信息包括崩溃时的内存运行数据、抓取的logcat日志、运行设备的信息、进程信息和应用程序基本信息。收集的这些信息的目的在实施例1中已阐述,在此不再赘述。
在上述实施例的基础上,还包括删除模块,用于在崩溃信息收集完成后,杀掉当前崩溃的进程。
在上述实施例的基础上,还包括初始化模块,具体用于指定存储崩溃信息的路径及初始化Shell命令。
以上所描述的系统实施例仅仅是示意性的,其中所述作为分离部件说明的单元可以是或者也可以不是物理上分开的,作为单元显示的部件可以是或者也可以不是物理单元,即可以位于一个地方,或者也可以分布到多个网络单元上。可以根据实际的需要选择其中的部分或者全部模块来实现本实施例方案的目的。本领域普通技术人员在不付出创造性的劳动的情况下,即可以理解并实施。
应该注意的是上述实施方式对本发明进行说明而不是对本发明进行限制,并且本领域技术人员在不脱离所附权利要求的范围的情况下可设计出替换实施方式。在权利要求中,不应将位于括号之间的任何参考符号构造成对权利要求的限制。单词“包含”不排除存在未列在权利要求中的元件或步骤。位于元件之前的单词“一”或“一个”不排除存在多个这样的元件。本发明可以借助于包括有若干不同元件的硬件以及借助于适当编程的计算机来实现。在列举了若干装置的单元权利要求中,这些装置中的若干个可以是通过同一个硬件项来具体体现。单词第一、第二、以及第三等的使用不表示任何顺序。可将这些单词解释为名称。
虽然结合附图描述了本发明的实施方式,但是本领域技术人员可以在不脱离本发明的精神和范围的情况下做出各种修改和变型,这样的修改和变型均落入由所附权利要求所限定的范围之内。