
1.本技术涉及计算机技术领域,具体而言,本技术涉及一种检测方法、装置、设备及计算机可读存储介质。
背景技术:2.现有技术中ios(iphone operating system,苹果公司开发的移动操作系统)的app(application,应用程序)的卡顿(即app的主线程中方法调用存在anr(application not responding,应用没有响应))反馈可能存在误报和漏查的情况。例如,基于fps(framespersecond,每秒帧数)的监控方案,当app的卡顿发生时,fps会有明显下滑,但是转场动画等特殊场景也存在fps下滑情况,从而导致误报。又例如,基于app的主线程乒乓ping/pong的方案,主线程出现堵塞直到空闲期间都无法收到pong回复,但是在获取堆栈期间获取的堆栈可能已经不是卡顿的主要原因。又例如,基于运行循环runloop的监控方案会把不同阶段时间分片,当某个时间片太长,基本认定发生了卡顿,但是应用闲置状态会常驻等待之前beforewaiting阶段,此阶段会存在误报可能。
技术实现要素:3.本技术针对现有的方式的缺点,提出一种针对检测方法、装置、设备及计算机可读存储介质,用以解决如何提升判断方法调用中是否存在anr的准确度的问题。
4.第一方面,本技术提供了一种检测方法,检测方法由内联钩子函数inline hook执行,包括:响应于应用触发的对主线程中方法的调用,调用由方法转换成的原始函数对应的第一函数,以用于通过第一函数确定调用原始函数的起始时刻;调用原始函数,以使应用执行对方法的调用;响应于对原始函数的调用结束,调用原始函数对应的第二函数,以通过第二函数确定调用原始函数的结束时刻;根据起始时刻和结束时刻,确定原始函数的执行时间段;当执行时间段大于预设响应阈值,则确定方法调用中存在应用没有响应anr。
5.在一个实施例中,在调用由方法转换成的原始函数对应的第一函数之前,还包括:将原始函数调用前的上下文信息保存到预设的存储区域,原始函数调用前的上下文信息包括原始函数调用前移动操作系统中全部寄存器的内容,以及移动操作系统的栈中的参数。
6.在一个实施例中,在将原始函数调用前的上下文信息保存到预设的存储区域之前,还包括:将移动操作系统的连接寄存器lr和帧指针保存到所述栈中,并将原始函数的超出临时寄存器数量的参数保存到栈中。
7.在一个实施例中,在调用由方法转换成的原始函数对应的第一函数之后,还包括:
将存储区域中的原始函数调用前的上下文信息恢复到栈中。
8.在一个实施例中,在调用原始函数之后,还包括:确定原始函数调用后的上下文信息,并将原始函数调用后的上下文信息保存到预设的存储区域,原始函数调用后的上下文信息包括原始函数调用后移动操作系统中全部寄存器的内容,以及移动操作系统的栈中的参数。
9.在一个实施例中,原始函数为引擎objc_msgsend函数,方法为静态库或系统函数。
10.在一个实施例中,当应用触发对主线程中至少两个方法的调用,且至少两个方法之间存在调用关系,至少两个方法中的任一方法抛出异常,以及任一方法对应的第二函数与除任一方法之外的其他方法对应的第二函数相同,则通过移动操作系统的lr,确定除任一方法之外的其他方法对应的第一函数,并将任一方法对应的第一函数丢弃。
11.第二方面,本技术提供了一种检测装置,检测装置通过inline hook执行,包括:第一处理模块,用于响应于应用触发的对主线程中方法的调用,调用由方法转换成的原始函数对应的第一函数,以用于通过第一函数确定调用原始函数的起始时刻;第二处理模块,用于调用原始函数,以使应用执行对方法的调用;第三处理模块,用于响应于对原始函数的调用结束,调用原始函数对应的第二函数,以通过第二函数确定调用原始函数的结束时刻;第四处理模块,用于根据起始时刻和结束时刻,确定原始函数的执行时间段;第五处理模块,用于当执行时间段大于预设响应阈值,则确定方法存在应用没有响应anr。
12.第三方面,本技术提供了一种电子设备,包括:处理器、存储器和总线;总线,用于连接处理器和存储器;存储器,用于存储操作指令;处理器,用于通过调用操作指令,执行本技术第一方面的检测方法。
13.第四方面,本技术提供了一种计算机可读存储介质,存储有计算机程序,计算机程序被用于执行本技术第一方面的检测方法。
14.本技术实施例提供的技术方案,至少具有如下有益效果:通过inline hook,确定调用原始函数的起始时刻和调用原始函数的结束时刻,根据起始时刻和结束时刻,确定原始函数的执行时间段;当执行时间段大于预设响应阈值,即主线程中方法的调用耗时大于预设响应阈值,则确定方法调用中存在anr;如此,通过inline hook确定主线程中方法的调用耗时,即原始函数的执行时间段,实现准确判断方法调用中是否存在anr,从而提升了判断方法调用中是否存在anr的准确度。
附图说明
15.为了更清楚地说明本技术实施例中的技术方案,下面将对本技术实施例描述中所需要使用的附图作简单地介绍。
16.图1为本技术实施例提供的系统架构的示意图;图2为本技术实施例提供的一种检测方法的流程示意图;图3为本技术实施例提供的检测方法的示意图;图4为本技术实施例提供的检测方法的示意图;
图5为本技术实施例提供的另一种检测方法的流程示意图;图6为本技术实施例提供的一种检测装置的结构示意图;图7为本技术实施例提供的一种电子设备的结构示意图。
具体实施方式
17.为使得本技术的发明目的、特征、优点能够更加的明显和易懂,下面将结合本技术实施例中的附图,对本技术实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本技术一部分实施例,而非全部实施例。基于本技术中的实施例,本领域技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都属于本技术保护的范围。
18.下面详细描述本技术的实施例,该实施例的示例在附图中示出,其中自始至终相同或类似的标号表示相同或类似的元件或具有相同或类似功能的元件。下面通过参考附图描述的实施例是示例性的,仅用于解释本技术,而不能解释为对本技术的限制。
19.本技术领域技术人员可以理解,除非特意声明,这里使用的单数形式“一”、“一个”、“所述”和“该”也可包括复数形式。应该进一步理解的是,本技术的说明书中使用的措辞“包括”是指存在特征、整数、步骤、操作、元件和/或组件,但是并不排除存在或添加一个或多个其他特征、整数、步骤、操作、元件、组件和/或它们的组。应该理解,当我们称元件被“连接”或“耦接”到另一元件时,它可以直接连接或耦接到其他元件,或者也可以存在中间元件。此外,这里使用的“连接”或“耦接”可以包括无线连接或无线耦接。这里使用的措辞“和/或”包括一个或更多个相关联的列出项的全部或任一单元和全部组合。
20.本技术实施例是针对云教育领域提供的一种检测方法,该检测方法涉及云技术的多种领域,例如云技术中的云计算、云服务等。
21.云教育(cloud computing education 简称:ccedu),是指基于云计算商业模式应用的教育平台服务。在云平台上,所有的教育机构,培训机构,招生服务机构,宣传机构,行业协会,管理机构,行业媒体,法律结构等都集中云整合成资源池,各个资源相互展示和互动,按需交流,达成意向,从而降低教育成本,提高效率。
22.云计算(cloud computing)是一种计算模式,它将计算任务分布在大量计算机构成的资源池上,使各种应用系统能够根据需要获取计算力、存储空间和信息服务。提供资源的网络被称为“云”。“云”中的资源在使用者看来是可以无限扩展的,并且可以随时获取,按需使用,随时扩展,按使用付费。
23.作为云计算的基础能力提供商,会建立云计算资源池(简称云平台,一般称为iaas(infrastructure as a service,基础设施即服务)平台,在资源池中部署多种类型的虚拟资源,供外部客户选择使用。云计算资源池中主要包括:计算设备(为虚拟化机器,包含操作系统)、存储设备、网络设备。
24.按照逻辑功能划分,在iaas(infrastructure as a service,基础设施即服务)层上可以部署paas(platform as a service,平台即服务)层,paas层之上再部署saas(software as a service,软件即服务)层,也可以直接将saas部署在iaas上。paas为软件运行的平台,如数据库、web容器等。saas为各式各样的业务软件,如web门户网站、短信群发器等。一般来说,saas和paas相对于iaas是上层。
25.所谓人工智能云服务,一般也被称作是aiaas(aias a service,中文为“ai即服
务”)。这是目前主流的一种人工智能平台的服务方式,具体来说aiaas平台会把几类常见的ai服务进行拆分,并在云端提供独立或者打包的服务。这种服务模式类似于开了一个ai主题商城:所有的开发者都可以通过api接口的方式来接入使用平台提供的一种或者是多种人工智能服务,部分资深的开发者还可以使用平台提供的ai框架和ai基础设施来部署和运维自已专属的云人工智能服务。
26.人工智能(artificial intelligence,ai)是利用数字计算机或者数字计算机控制的机器模拟、延伸和扩展人的智能,感知环境、获取知识并使用知识获得最佳结果的理论、方法、技术及应用系统。换句话说,人工智能是计算机科学的一个综合技术,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器。人工智能也就是研究各种智能机器的设计原理与实现方法,使机器具有感知、推理与决策的功能。
27.人工智能技术是一门综合学科,涉及领域广泛,既有硬件层面的技术也有软件层面的技术。人工智能基础技术一般包括如传感器、专用人工智能芯片、云计算、分布式存储、大数据处理技术、操作/交互系统、机电一体化等技术。人工智能软件技术主要包括计算机视觉技术、语音处理技术、自然语言处理技术以及机器学习/深度学习、自动驾驶、智慧交通等几大方向。
28.为了更好的理解及说明本技术实施例的方案,下面对本技术实施例中所涉及到的一些技术用语进行简单说明。
29.hook:钩子hook指使用自定义函数覆盖;hook实际上是一个处理消息的程序段,通过系统调用,把程序段挂入系统;每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,即钩子函数先得到控制权,钩子函数可以加工处理该消息,也可以不作处理而继续传递该消息,还可以强制结束该消息的传递。
30.动态hook:指在程序运行过程中完成hook。
31.inline hook:通过修改原函数部分指令,使用一个跳转或者其他指令到达hook的目的。
32.sp:sp(stackpoint,栈指针)表示当前栈帧的顶部。
33.fp:fp(framepoint,帧指针)表示当前栈帧的底部。
34.栈帧(stack frame):每一次函数的调用,都会在调用栈(call stack)上维护一个独立的栈帧,每个独立的栈帧一般包括:函数的返回地址和参数;临时变量,其中,临时变量包括函数的非静态局部变量以及编译器自动生成的其他临时变量;函数调用的上下文。栈是从高地址向低地址延伸,一个函数的栈帧用ebp和esp这两个寄存器来划定范围,其中,ebp指向当前的栈帧的底部,esp始终指向栈帧的顶部;ebp寄存器又被称为fp(framepoint,帧指针),esp寄存器又被称为sp(stackpoint,栈指针)。
35.anr:anr(application not responding,应用没有响应)通常是主线程执行耗时操作,应用无法响应用户事件。
36.cfa:cfa(canonical frame address,标准框架地址)指调用者栈帧中调用点处的栈指针值。cfa表示一个基地址,用于作为当前函数中的其它地址的起始地址,使得其它地址可以用与该基地址的偏移来表示。
37.fishhook:fishhook是一个动态修改链接mach
‑
o文件的工具;fishhook利用mach
‑
o文件加载原理,通过修改懒加载和非懒加载两个表指针达到c函数hook的目的。
38.方法:方法可以是类的方法,类的方法可以分为公有方法、私有方法、类方法、静态方法等;其中,公有方法:在类中和类外都可以调用的方法;私有方法:不能被类外部调用,在方法前面加上双下划线就是私有方法;类方法:被classmethod()函数处理过的函数,能被类所调用,也能被对象所调用;静态方法:相当于全局函数,可以被类直接调用,可以被所有实例化对象共享,通过staticmethod()函数定义,静态方法没有self参数。
39.主线程:主线程是当一个程序启动时,就有一个进程被操作系统创建,与此同时一个线程也立刻运行;主线程是程序开始时就执行的,如果需要再创建线程,那么创建的线程就是这个主线程的子线程,每个进程至少都有一个主线程;主线程的重要性体现在两方面:1、主线程是产生其他子线程的线程;2、通常主线程必须最后完成执行,例如执行各种关闭动作。
40.objc_msgsend:objc_msgsend函数是所有oc方法调用的核心引擎,objc_msgsend负责查找真实的类或者对象方法的实现,并去执行这些方法函数。所有oc方法调用在编译时都会转化为对c函数objc_msgsend的调用。
41.ios是使用oc语言进行编写,objc_msgsend是oc中的核心函数,所有的方法的调用最终都会转化成对objc_msgsend函数的调用,objc_msgsend函数原型为objc_msgsend(id self,sel op,...),第一个是消息接收的对象实例,第二个参数是要执行的方法,...为可变参数。为了优化ios的性能,该函数内部使用汇编语言实现,而且不同平台对应不同的汇编文件。ios真机是使用arm64汇编进行编写,arm64有32个长度为64bit的通用寄存器:x0~x30和sp,可以只使用每个通用寄存器64bit中的32bit:w0~w30,其中,前8个寄存器x0~x7用于函数调用时传递参数,同时x0寄存器也可以作为函数返回值的寄存器。x8寄存器用于间接寻址(当函数返回的内容>16bytes时,该返回内容会被放入到内存中,然后将该内存地址存入x8寄存器)。特殊寄存器如下:(1)sp寄存器指向当前栈帧的栈顶(低地址),可以通过移动sp的位置为栈分配或释放内存空间。
42.(2)x29通常作为fp寄存器,指向当前栈帧的栈底(高地址)。
43.(3)x30通常作为lr(link register,连接寄存器),lr有两个作用:1、保存子程序的返回地址,2、当异常发生时,用来保存异常的返回地址。
44.(4)pc,程序计数器,用于指向下一条指令。
45.在ios中,当函数的参数的数量超过临时寄存器(x0~x7)的数量,则会将多余的参数放到栈中进行保存,例如,函数的参数的数量超过8,则将多余的参数放到栈中进行保存;所以在hookobjc_msgsend时,不能在栈中直接保存寄存器,可能会被覆盖。ios中栈的结构分为若干栈帧(frame),每个栈帧对应一个函数调用,栈指针sp表示当前栈的顶部,由于ios系统的栈是向下生长,sp是栈地址的最小值。帧指针fp表示当前栈帧的底部,fp指向的地址保存了上一个栈帧的返回地址和fp,当对objc_msgsend进行hook时,需要拷贝上一个栈帧用来保存函数的上下文,以防止函数的参数丢失。
46.本技术实施例提供的方案涉及云技术,下面以具体的实施例对本技术的技术方案以及本技术的技术方案如何解决上述技术问题进行详细说明。下面这几个具体的实施例可以相互结合,对于相同或相似的概念或过程可能在某些实施例中不再赘述。下面将结合附图,对本技术的实施例进行描述。
47.本技术实施例所提供的方案可以适用于云技术领域中任意需要检测主线程中方法调用是否存在anr的应用场景,通过该方案可以针对主线程中方法调用进行如下检测:通过inline hook确定主线程中方法的调用耗时,实现准确检测到方法调用中是否存在anr。
48.为了更好的理解本技术实施例提供的方案,下面结合具体的一个应用场景对该方案进行说明。
49.在一个实施例中,图1中示出了本技术实施例所适用的一种检测的系统架构示意图,可以理解的是,本技术实施例所提供的检测方法可以适用于但不限于应用于如图1所示的应用场景中。
50.本示例中,如图1所示,该示例中的检测的系统架构可以包括但不限于服务器110和终端120,服务器110和终端120之间可以通过网络进行交互。当终端120的ios的应用触发对主线程中方法的调用,则服务器110中运行的inline hook调用由方法转换成的原始函数对应的第一函数,以用于通过第一函数确定调用原始函数的起始时刻;inline hook调用原始函数,以使应用执行对方法的调用;inline hook响应于对原始函数的调用结束,调用原始函数对应的第二函数,以通过第二函数确定调用原始函数的结束时刻;inline hook根据起始时刻和结束时刻,确定原始函数的执行时间段;当执行时间段大于预设响应阈值,inline hook则确定方法调用中存在anr。
51.可理解,上述仅为一种示例,本实施例在此不作限定。
52.其中,终端120可以是智能手机(如android手机、ios手机等)、手机模拟器、平板电脑、笔记本电脑、数字广播接收器、mid(mobile internet devices,移动互联网设备)、pda(个人数字助理)、台式计算机、车载终端(例如车载导航终端)、智能音箱、智能手表等。服务器110可以是独立的物理服务器,也可以是多个物理服务器构成的服务器集群或者分布式系统,还可以是提供云服务、云数据库、云计算、云函数、云存储、网络服务、云通信、中间件服务、域名服务、安全服务、cdn(content delivery network,内容分发网络)、以及大数据和人工智能平台等基础云计算服务的云服务器或服务器集群。上述网络可以包括但不限于:有线网络,无线网络,其中,该有线网络包括:局域网、城域网和广域网,该无线网络包括:蓝牙、wi
‑
fi及其他实现无线通信的网络。具体也可基于实际应用场景需求确定,在此不作限定。
53.参见图2,图2示出了本技术实施例提供的一种检测方法的流程示意图,作为一可选实施方式,该方法可以由inline hook执行,为了描述方便,在下文的一些可选实施例的描述中,将以inline hook作为该方法执行主体为例进行说明。如图2所示,本技术实施例提供的检测方法包括如下步骤:s101,响应于应用触发的对主线程中方法的调用,调用由方法转换成的原始函数对应的第一函数,以用于通过第一函数确定调用原始函数的起始时刻。
54.在一个实施例中,ios的应用触发对主线程中方法的调用,应用将主线程中方法的调用转化成对原始函数的调用,inline hook调用原始函数对应的第一函数。例如,原始函数可以为objc_msgsend函数,inline hook调用objc_msgsend函数对应的第一函数,第一函数为before_objc_msgsend函数,before_objc_msgsend函数用于记录inline hook调用objc_msgsend函数的起始时间,即起始时刻。
55.在一个实施例中,在调用由方法转换成的原始函数对应的第一函数之前,还包括:
将原始函数调用前的上下文信息保存到预设的存储区域,原始函数调用前的上下文信息包括原始函数调用前移动操作系统中全部寄存器的内容,以及移动操作系统的栈中的参数。
56.在一个实施例中,存储区域可以为预设的临时空间。原始函数调用前的上下文信息可以是原始函数调用前的上下文环境。原始函数调用前的上下文环境包括原始函数调用前移动操作系统ios中全部寄存器的内容,以及原始函数调用前ios的栈中的参数。例如,原始函数调用前的移动操作系统ios中全部寄存器的内容可以包括:原始函数调用前32个长度为64bit的通用寄存器的内容,其中,这32个通用寄存器分别为x0~x30和sp。
57.在一个实施例中,在将原始函数调用前的上下文信息保存到预设的存储区域之前,还包括:将移动操作系统的lr(link register,连接寄存器)和帧指针保存到栈中,并将原始函数的超出临时寄存器数量的参数保存到栈中。
58.在一个实施例中,当原始函数的参数的数量超过临时寄存器的数量,则将超出的参数放到栈中进行保存。例如,临时寄存器为寄存器x0~x7,寄存器x0~x7的数量为8,当原始函数的参数数量10超过8,则将超出的2个参数放到栈中进行保存。
59.在一个实施例中,在调用由方法转换成的原始函数对应的第一函数之后,还包括:将存储区域中的原始函数调用前的上下文信息恢复到栈中。
60.在一个实施例中,存储区域可以为预设的临时空间。原始函数调用前的上下文信息可以是原始函数调用前的上下文环境。inline hook从临时空间中恢复原始函数调用前的上下文环境,即将临时空间中的原始函数调用前的上下文环境恢复到栈中。原始函数调用前的上下文环境包括原始函数调用前移动操作系统ios中全部寄存器的内容,以及原始函数调用前ios的栈中的参数。例如,全部寄存器的内容可以包括:原始函数调用前32个长度为64bit的通用寄存器的内容,其中,这32个通用寄存器分别为x0~x30和sp。
61.在一个实施例中,在将存储区域中的原始函数调用前的上下文信息恢复到栈中之后,inline hook调用原始函数,例如,原始函数为objc_msgsend函数。
62.s102,调用原始函数,以使应用执行对方法的调用。
63.在一个实施例中,inline hook调用原始函数,从而实现应用对主线程中方法的调用,例如,原始函数为objc_msgsend函数。
64.在一个实施例中,在调用原始函数之后,还包括:确定原始函数调用后的上下文信息,并将原始函数调用后的上下文信息保存到预设的存储区域,原始函数调用后的上下文信息包括原始函数调用后移动操作系统中全部寄存器的内容,以及移动操作系统的栈中的参数。
65.在一个实施例中,存储区域可以为预设的临时空间。原始函数调用后的上下文信息可以是原始函数调用后的上下文环境。原始函数调用后的上下文环境包括原始函数调用后移动操作系统ios中全部寄存器的内容,以及原始函数调用后ios的栈中的参数。例如,原始函数调用后的移动操作系统ios中全部寄存器的内容可以包括:原始函数调用后32个长度为64bit的通用寄存器的内容,其中,这32个通用寄存器分别为x0~x30和sp。
66.s103,响应于对原始函数的调用结束,调用原始函数对应的第二函数,以通过第二函数确定调用原始函数的结束时刻。
67.在一个实施例中,当inline hook调用原始函数的过程结束,inline hook调用原始函数对应的第二函数。例如,原始函数可以为objc_msgsend函数,inline hook调用objc_msgsend函数对应的第二函数,第二函数为after_objc_msgsend函数,after_objc_msgsend函数用于记录inline hook调用objc_msgsend函数的结束时间,即结束时刻。
68.在一个实施例中,将lr的值作为原始函数对应的第二函数的参数,以用于确定原始函数对应的第一函数。
69.举例说明,将lr的值作为某个原始函数对应的after_objc_msgsend函数的参数,即将lr的值赋值给通用寄存器x2,以用于确定该原始函数对应的before_objc_msgsend函数。
70.在一个实施例中,当应用触发对主线程中至少两个方法的调用、至少两个方法之间存在调用关系,且至少两个方法中的任一方法抛出异常,则通过ios的lr,确定除任一方法之外的其他方法对应的第一函数。
71.在一个实施例中,当应用触发对主线程中至少两个方法的调用,且至少两个方法之间存在调用关系,至少两个方法中的任一方法抛出异常,以及任一方法对应的第二函数与除任一方法之外的其他方法对应的第二函数相同,则通过移动操作系统的lr,确定除任一方法之外的其他方法对应的第一函数,并将任一方法对应的第一函数丢弃。
72.在一个实施例中,当应用触发对主线程中任意两个方法(方法a和方法b)的调用、两个方法之间存在调用关系、两个方法中的方法b抛出异常,且此时方法a对应的第二函数与方法b对应的第二函数相同,即该第二函数同时对应(关联)了方法a对应的第一函数和方法b对应的第一函数;则通过ios的lr,确定该第二函数应该与方法a对应的第一函数相对应,该第二函数不应该与方法b对应的第一函数相对应,从而正确的确定了该第二函数对应的第一函数。
73.举例说明,对主线程中多个方法的调用,实际是对各方法对应的原始函数的调用。如图3所示,方法a对应的原始函数为a函数,a函数为objc_msgsend函数,a函数对应的第一函数为a函数对应的before_objc_msgsend函数,a函数对应的第二函数为a函数对应的after_objc_msgsend函数;方法b对应的原始函数为b函数,b函数为objc_msgsend函数,b函数对应的第一函数为b函数对应的before_objc_msgsend函数,b函数对应的第二函数为b函数对应的after_objc_msgsend函数。主线程中的其他函数在调用a函数,a函数调用b函数。a函数调用b函数会触发inline hook对b函数对应的before_objc_msgsend函数、b函数,以及b函数对应的after_objc_msgsend函数的调用。
74.当b函数没有发生crash(异常)的情况,则整个数据流的次序是:次序1、次序2、次序3、次序4、次序5和次序6;其中,次序1是调用a函数对应的before_objc_msgsend函数,次序2是调用a函数,次序3是调用b函数对应的before_objc_msgsend函数,次序4是调用b函数,次序5是调用b函数对应的after_objc_msgsend函数,次序6是调用a函数对应的after_objc_msgsend函数。根据a函数对应的after_objc_msgsend函数和a函数对应的before_objc_msgsend函数,确定a函数的调用耗时,即通过a函数对应的after_objc_msgsend函数和a函数对应的before_objc_msgsend函数之间进行求差计算,得到a函数的调用耗时;根据b函数对应的after_objc_msgsend函数和b函数对应的before_objc_msgsend函数,确定b函数的调用耗时,即通过b函数对应的after_objc_msgsend函数和b函数对应的before_objc_
msgsend函数之间进行求差计算,得到b函数的调用耗时。
75.当b函数发生crash(异常)的情况,即try
‑
catch函数捕获到b函数出现crash的情况,则整个数据流的次序是:次序1、次序2、次序3、次序7和次序6;其中,次序1是调用a函数对应的before_objc_msgsend函数,次序2是调用a函数,次序3是调用b函数对应的before_objc_msgsend函数,次序7是调用b函数,次序6是调用a函数对应的after_objc_msgsend函数。b函数实际对应的after_objc_msgsend函数并没有调用,而是直接调用了a函数对应的after_objec_msgsend函数,此时是b函数对应的before_objc_msgsend函数与a函数对应的after_objec_msgsend函数相互关联,这样a函数对应的after_objec_msgsend函数同时关联了a函数对应的before_objc_msgsend函数和b函数对应的before_objc_msgsend函数,即此时b函数对应的第二函数与a函数对应的第二函数相同,此时b函数对应的第二函数与a函数对应的第二函数都是a函数对应的after_objec_msgsend。因此,如图4所示,将lr的值作为a函数对应的after_objc_msgsend函数的参数,用于确定a函数对应的after_objec_msgsend应该关联a函数的before_objc_msgsend函数,并将b函数对应的before_objc_msgsend函数丢弃,从而避免了将a函数对应的after_objec_msgsend关联b函数对应的before_objc_msgsend函数所造成的调用耗时计算错误。
76.s104,根据起始时刻和结束时刻,确定原始函数的执行时间段。
77.在一个实施例中,将结束时刻和起始时刻之间进行求差计算,得到原始函数的执行时间段,其中,原始函数的执行时间段为原始函数的调用耗时。
78.s105,当执行时间段大于预设响应阈值,则确定方法调用中存在应用没有响应anr。
79.举例说明,预设响应阈值可以取值为100ms(毫秒),当原始函数的调用耗时大于100ms,则确定app的方法调用中存在anr,可以精确的对产生anr的原始函数进行捕获。
80.在一个实施例中,原始函数为引擎objc_msgsend函数,方法为静态库或系统函数。
81.需要说明的,fishhook是存在局限性的,不能对静态库以及系统函数进行hook。静态库以及系统函数可以转换为原始函数,inline hook可以对静态库以及系统函数的调用耗时进行检测。
82.本技术实施例中,通过inline hook,确定调用原始函数的起始时刻和调用原始函数的结束时刻,根据起始时刻和结束时刻,确定原始函数的执行时间段;当执行时间段大于预设响应阈值,即主线程中方法的调用耗时大于预设响应阈值,则确定方法调用中存在anr;如此,通过inline hook确定主线程中方法的调用耗时,即原始函数的执行时间段,实现准确判断方法调用中是否存在anr,从而提升了判断方法调用中是否存在anr的准确度。
83.为了更好的理解本技术实施例所提供的方法,下面结合具体应用场景的示例对本技术实施例的方案进行进一步说明。
84.参见图5,图5示出了本技术实施例提供的一种检测方法的流程示意图,作为一可选实施方式,该方法可以由inline hook执行,为了描述方便,在下文的一些可选实施例的描述中,将以inline hook作为该方法执行主体为例进行说明。如图5所示,本技术实施例提供的检测方法包括如下步骤:s201,将ios的连接寄存器lr和帧指针fp保存到ios的栈中。
85.s202,复制ios的栈帧,并将原始函数的超出临时寄存器数量的参数保存到栈中。
86.在一个实施例中,当原始函数的参数的数量超过临时寄存器的数量,则将超出临时寄存器数量的参数保存到栈中;通过复制ios的栈帧,可以将超出临时寄存器数量的参数复制下来。例如,临时寄存器为寄存器x0~x7,寄存器x0~x7的数量为8,当原始函数的参数数量15超过8,则将超出的7个参数放到栈中进行保存,通过复制ios的栈帧,可以将超出的7个参数复制下来。
87.s203,重置cfa,通过规范cfa,回溯到栈的顶层。
88.举例说明,a函数调用b函数,b函数调用c函数;重置cfa,通过规范cfa,将w29~w30重复赋值,从而可以一直回溯到栈的顶层,即从c函数一直回溯到a函数。
89.s204,保存原始函数调用前的上下文环境。
90.在一个实施例中,将原始函数调用前的上下文环境保存到预设的临时空间,原始函数调用前的上下文环境包括原始函数调用前ios中全部寄存器的内容,以及ios的栈中的参数。例如,原始函数调用前的ios中全部寄存器的内容可以包括:原始函数调用前32个长度为64bit的通用寄存器的内容,其中,这32个通用寄存器分别为x0~x30和sp。
91.s205,调用原始函数对应的before_objc_msgsend函数,用于记录调用原始函数的起始时间。
92.举例说明,原始函数可以为objc_msgsend函数,inline hook调用objc_msgsend函数对应的第一函数,第一函数为before_objc_msgsend函数,before_objc_msgsend函数用于记录inline hook调用objc_msgsend函数的起始时间,即起始时刻。
93.s206,将临时空间中的原始函数调用前的上下文环境恢复到栈中。
94.在一个实施例中,inline hook将临时空间中的原始函数调用前的上下文环境恢复到栈中。原始函数调用前的上下文环境包括原始函数调用前ios中全部寄存器的内容,以及原始函数调用前ios的栈中的参数。例如,全部寄存器的内容可以包括:原始函数调用前32个长度为64bit的通用寄存器的内容,其中,这32个通用寄存器分别为x0~x30和sp。
95.s207,调用原始函数。
96.在一个实施例中,inline hook调用原始函数objc_msgsend,从而实现应用对主线程中方法的调用。
97.s208,保存原始函数调用后的上下文环境。
98.在一个实施例中,将原始函数调用后的上下文环境保存到临时空间,原始函数调用后的上下文信息包括原始函数调用后ios中全部寄存器的内容,以及ios的栈中的参数。例如,原始函数调用后的ios中全部寄存器的内容可以包括:原始函数调用后32个长度为64bit的通用寄存器的内容,其中,这32个通用寄存器分别为x0~x30和sp。
99.s209,调用原始函数对应的after_objc_msgsend函数,用于记录调用原始函数的结束时间。
100.在一个实施例中,当inline hook调用原始函数的过程结束,inline hook调用原始函数对应的第二函数。例如,原始函数可以为objc_msgsend函数,inline hook调用objc_msgsend函数对应的第二函数,第二函数为after_objc_msgsend函数,after_objc_msgsend函数用于记录inline hook调用objc_msgsend函数的结束时间,即结束时刻。将lr的值作为原始函数对应的第二函数的参数,以用于确定原始函数对应的第一函数。例如,将lr的值作为原始函数对应的after_objc_msgsend函数的参数,即将lr的值赋值给通用寄存器x2,以
用于确定该原始函数对应的before_objc_msgsend函数。
101.s210,将结束时间和起始时间之间进行求差计算,得到原始函数的调用耗时。
102.s211,当原始函数的调用耗时大于预设响应阈值,则确定app的方法调用中存在anr。
103.在一个实施例中,当原始函数的调用耗时不大于预设响应阈值,则确定app的方法调用中不存在anr。
104.s212,将临时空间中的原始函数调用后的上下文环境恢复到栈中。
105.在一个实施例中,inline hook将临时空间中的原始函数调用后的上下文环境恢复到栈中。原始函数调用后的上下文环境包括原始函数调用后ios中全部寄存器的内容,以及原始函数调用后ios的栈中的参数。例如,原始函数调用后的ios中全部寄存器的内容可以包括:原始函数调用后32个长度为64bit的通用寄存器的内容,其中,这32个通用寄存器分别为x0~x30和sp。
106.s213,释放保存在ios栈中的lr、fp和栈帧。
107.本技术实施例中,通过inline hook对主线程的所有函数(方法)的调用耗时进行监控,当app的函数调用中发生anr时,可以精确的捕获到产生anr的函数,不存在误报和漏报的可能。
108.基于相同的发明构思,本技术实施例还提供了一种检测装置,检测装置通过inline hook执行,该装置的结构示意图如图6所示,检测装置40,包括第一处理模块401、第二处理模块402、第三处理模块403、第四处理模块404和第五处理模块405。
109.第一处理模块401,用于响应于应用触发的对主线程中方法的调用,调用由方法转换成的原始函数对应的第一函数,以用于通过第一函数确定调用原始函数的起始时刻;第二处理模块402,用于调用原始函数,以使应用执行对方法的调用;第三处理模块403,用于响应于对原始函数的调用结束,调用原始函数对应的第二函数,以通过第二函数确定调用原始函数的结束时刻;第四处理模块404,用于根据起始时刻和结束时刻,确定原始函数的执行时间段;第五处理模块405,用于当执行时间段大于预设响应阈值,则确定方法存在应用没有响应anr。
110.在一个实施例中,在调用由方法转换成的原始函数对应的第一函数之前,第一处理模块401,还用于:将原始函数调用前的上下文信息保存到预设的存储区域,原始函数调用前的上下文信息包括原始函数调用前移动操作系统中全部寄存器的内容,以及移动操作系统的栈中的参数。
111.在一个实施例中,在将原始函数调用前的上下文信息保存到预设的存储区域之前,第一处理模块401,还用于:将移动操作系统的连接寄存器lr和帧指针保存到所述栈中,并将原始函数的超出临时寄存器数量的参数保存到栈中。
112.在一个实施例中,第一处理模块401,还用于:将存储区域中的原始函数调用前的上下文信息恢复到栈中。
113.在一个实施例中,在调用原始函数之后,第二处理模块402,还用于:
确定原始函数调用后的上下文信息,并将原始函数调用后的上下文信息保存到预设的存储区域,原始函数调用后的上下文信息包括原始函数调用后移动操作系统中全部寄存器的内容,以及移动操作系统的栈中的参数。
114.在一个实施例中,原始函数为引擎objc_msgsend函数,方法为静态库或系统函数。
115.在一个实施例中,第一处理模块401,还用于:当应用触发对主线程中至少两个方法的调用,且至少两个方法之间存在调用关系,至少两个方法中的任一方法抛出异常,以及任一方法对应的第二函数与除任一方法之外的其他方法对应的第二函数相同,则通过移动操作系统的lr,确定除任一方法之外的其他方法对应的第一函数,并将任一方法对应的第一函数丢弃。
116.应用本技术实施例,至少具有如下有益效果:通过inline hook,确定调用原始函数的起始时刻和调用原始函数的结束时刻,根据起始时刻和结束时刻,确定原始函数的执行时间段;当执行时间段大于预设响应阈值,即主线程中方法的调用耗时大于预设响应阈值,则确定方法调用中存在anr;如此,通过inline hook确定主线程中方法的调用耗时,即原始函数的执行时间段,实现准确判断方法调用中是否存在anr,从而提升了判断方法调用中是否存在anr的准确度。
117.基于相同的发明构思,本技术实施例还提供了一种电子设备,该电子设备的结构示意图如图7所示,该电子设备9000包括至少一个处理器9001、存储器9002和总线9003,至少一个处理器9001均与存储器9002电连接;存储器9002被配置用于存储有至少一个计算机可执行指令,处理器9001被配置用于执行该至少一个计算机可执行指令,从而执行如本技术中任意一个实施例或任意一种可选实施方式提供的任意一种检测方法的步骤。
118.进一步,处理器9001可以是fpga(field-programmable gate array,现场可编程门阵列)或者其它具有逻辑处理能力的器件,如mcu(microcontroller unit,微控制单元)、cpu(central process unit,中央处理器)。
119.应用本技术实施例,至少具有如下有益效果:通过inline hook,确定调用原始函数的起始时刻和调用原始函数的结束时刻,根据起始时刻和结束时刻,确定原始函数的执行时间段;当执行时间段大于预设响应阈值,即主线程中方法的调用耗时大于预设响应阈值,则确定方法调用中存在anr;如此,通过inline hook确定主线程中方法的调用耗时,即原始函数的执行时间段,实现准确判断方法调用中是否存在anr,从而提升了判断方法调用中是否存在anr的准确度。
120.基于相同的发明构思,本技术实施例还提供了一种计算机可读存储介质,存储有计算机程序,该计算机程序用于被处理器执行时实现本技术中任意一个实施例或任意一种可选实施方式提供的任意一种检测方法的步骤。
121.本技术实施例提供的计算机可读存储介质包括但不限于任何类型的盘(包括软盘、硬盘、光盘、cd
‑
rom、和磁光盘)、rom(read
‑
only memory,只读存储器)、ram(random access memory,随即存储器)、eprom(erasable programmable read
‑
only memory,可擦写可编程只读存储器)、eeprom(electrically erasable programmable read
‑
only memory,电可擦可编程只读存储器)、闪存、磁性卡片或光线卡片。也就是,可读存储介质包括由设备(例如,计算机)以能够读的形式存储或传输信息的任何介质。
122.应用本技术实施例,至少具有如下有益效果:
通过inline hook,确定调用原始函数的起始时刻和调用原始函数的结束时刻,根据起始时刻和结束时刻,确定原始函数的执行时间段;当执行时间段大于预设响应阈值,即主线程中方法的调用耗时大于预设响应阈值,则确定方法调用中存在anr;如此,通过inline hook确定主线程中方法的调用耗时,即原始函数的执行时间段,实现准确判断方法调用中是否存在anr,从而提升了判断方法调用中是否存在anr的准确度。
123.本技术实施例还提供了一种包含指令的计算机程序产品,当其在计算机设备上运行时,使得计算机设备执行上述各个方法实施例所提供的检测方法。
124.本技术领域技术人员可以理解,可以用计算机程序来实现这些结构图和/或框图和/或流图中的每个框以及这些结构图和/或框图和/或流图中的框的组合。本技术领域技术人员可以理解,可以将这些计算机程序产品提供给通用计算机、专业计算机或其他可编程数据处理方法的处理器来实现,从而通过计算机或其他可编程数据处理方法的处理器来执行本技术公开的结构图和/或框图和/或流图的框或多个框中指定的方案。
125.本技术领域技术人员可以理解,本技术中已经讨论过的各种操作、方法、流程中的步骤、措施、方案可以被交替、更改、组合或删除。进一步地,具有本技术中已经讨论过的各种操作、方法、流程中的其他步骤、措施、方案也可以被交替、更改、重排、分解、组合或删除。进一步地,现有技术中的具有与本技术中公开的各种操作、方法、流程中的步骤、措施、方案也可以被交替、更改、重排、分解、组合或删除。
126.以上所述仅是本技术的部分实施方式,应当指出,对于本技术领域的普通技术人员来说,在不脱离本技术原理的前提下,还可以做出若干改进和润饰,这些改进和润饰也应视为本技术的保护范围。