当前位置: 首页 > 科技观察

使用HOOK实现响应速度秒级测试_0

时间:2023-03-15 20:25:49 科技观察

作者|金建超,杨晨,单位:中国移动智能家居运营中心实验室对应用的性能提出了更高的要求。当前的性能测试技术跟不上移动应用的开发速度,测试效率低下,测试结果无法反映真实的用户体验。本文采用Hook技术实现Android应用响应速度的秒级测试,旨在为移动应用性能测试提供新的思路。os:测试士兵!产品棋子!Part01Android平台Hook技术Android操作系统有自己的事件分发机制。应用程序、应用程序触发事件、后台逻辑处理都是按照事件流程一步步执行的。钩子(hook)是在事件传递到端点之前拦截监听事件的传递,就像钩子钩住事件一样,在钩住事件的时候可以处理一些特定的事件,其本质是劫持函数称呼。1.1AndroidHook工作流程Hook的原理是改变目标函数的运行方向。Android是基于Linux内核的操作系统。每个Android进程都有自己独立的进程空间。实现Hook首先需要在目标进程空间注入代码,让代码在目标进程空间有对应的地址。最后,修改寄存器。要执行的函数的地址。Android中常用ptrace函数附加进程,mmap函数分配临时内存存放代码,dlopen函数加载动态链接库文件实现Hook。具体过程如下:使用ptraceattach附加到目标进程;调用mmap分配内存,写入内存注入so文件;调用dlopen打开注入的so文件,通过dlsym获取入口函数地址;使用ptrace_call调用入口函数;使用ptracedetach释放目标进程;两种开发模式,基于AndroidSDK的Java语言开发,以及基于AndroidNDK的NativeC/C++语言开发。根据APIHook对应的API,AndroidHook分为两种,一种是Java层Hook,一种是Native层Hook。Java层hook主要是通过注入Android平台的虚拟机和Java反射来改变Android虚拟机调用函数的方式,从而达到Java函数重定向的目的。常见框架有Xposed、CydiaSubstrate等,Native层Hook主要针对使用NDK开发的so库文件,包括Android操作系统Linux底层函数的重定向,通过修改全局偏移表GOT表或者so库文件(ELF格式文件)中的符号表SYM表,实现函数重定向。常见的框架有DeXposed、AndFix等。1.3Xposed框架Xposed是目前Android平台上使用最广泛的开源Hook框架。该框架通过替换/system/bin/app_process程序来控制Zygote进程,使系统在启动时加载XposedBridge.jar文件,从而完成Zygote进程及其对创建的Dalvik虚拟机的劫持。Xposed框架的主要功能是建立模块安装平台。安装Xposed框架后,开发者可以自定义开发各种功能模块,添加到xposed安装程序中,实现修改目标应用的功能,如修改手机序列号、GPS坐标、电话号码、运营商等等。当其他应用程序尝试读取这些信息时,它们会返回修改后的值或随机数。Part02测试工具设计与实现Android应用在运行过程中会调用系统提供的API。通过hook系统API获取它们的调用信息,然后分析API的调用关系和调用时间,实现系统API之间的调用。耗时统计。基于这一原理,本文设计了一套Android应用程序响应时间测试工具。2.1设计方案本文实现的Android应用程序响应时间测试工具总体架构如图2所示,包括xposed模块和分析模块。xposed模块负责事件获取和信息输出。它的主要功能是获取Android系统运行过程中的点击事件信息和绘图事件信息,并输出到logcat。分析模块监控logcat日志,分析收集到的信息并计算响应时间。图2响应时间测试工具架构图2.2点击事件HOOK实现Android应用程序使用事件驱动与用户交互。当用户触摸屏幕时,会产生点击事件(MotionEvent),然后通过事件分发传递给具体的业务进行相关处理。点击事件的分发过程主要由以下三个函数实现:dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()。一个完整的用户点击屏幕操作流程如下:用户触摸产生点击事件,调用Activity.dispatchTouchEvent()传递给Activity,Activity收到事件后,调用ViewGroup.dispatchTouchEvent()传递ViewGroup,ViewGroup收到事件后调用ViewGroup。onInterceptTouchEvent()确认事件是否被拦截。如果没有拦截,找到当前点击的子View,调用View的dispatchTouchEvent()实现事件传递,View收到事件后调用View.onTouchEvent()处理事件,最终完成点击事件。消耗。从上面的事件分发流程可以看出,点击事件的分发是从Activity.dispatchTouchEvent()开始的,所以我们选择这个函数作为点击的开始时间。使用Xposed框架实现Activity.dispatchTouchEvent()的Hook,在函数执行前输出相应的日志信息,包括事件Tag和事件时间戳。具体实现代码如下:/***Function:HookdispatchTouchEvent,获取点击事件Timestamp*/findAndHookMethod("android.app.Activity,loadPackageParam.classLoader,"dispatchTouchEvent",MotionEvent.class,newXC_MethodHook(){@OverrideprotectedvoidbeforeHookedMethod(MethodHookParamparam)throwsThrowable{super.beforeHookedMethod;/Method(param)/日志输出点击事件时间戳Log.d("speedtest","TouchTimestamp:"+System.currentTimeMillis()+"ms");}@OverrideprotectedvoidafterHookedMethod(MethodHookParamparam)throwsThrowable{super.afterHookedMethod(param);}});2.3绘制事件HOOK实现Android系统的显示过程可以简单概括为应用层进行测量,布局,绘制,完成后将Surface数据存储到匿名共享内存中,SurfaceFlinger将多个Surface缓存数据合成,提交到屏幕的后台缓冲区,然后将数据更新到屏幕en通过Android的刷新机制,最终通过应用层的不断绘制和屏幕的不断刷新,一帧一帧地显示出来。Android应用的显示过程包括Application端渲染和系统端渲染两部分,根据Xposed框架的适用范围和Hooking的难易程度,我们选择应用端渲染作为Hook目标。Android中的任何布局、任何控件,其实都是直接或间接继承自View的。所有视图都遵循相同的绘制过程。Measure和Layout用于确定当前需要绘制的View的大小和位置。通过绘制(Draw)到Surface。View的绘制过程可以细分如下:绘制背景:drawBackground(canvas);画自己:onDraw(canvas);绘制子视图:onDraw(canvas);绘制前景色和滚动条:onDrawForeground(canvas)。根据以上分析,我们选择View.onDrawForeground()作为目标函数,通过Xposed框架实现Hook,输出函数执行前后相应的日志信息,包括事件Tag和事件时间戳。具体实现代码如下:/***Function:HookdispatchDraw,getdrawingeventtimestamp*/findAndHookMethod("android.view.View",loadPackageParam.classLoader,"onDrawForeground",Canvas.class,newXC_MethodHook(){@OverrideprotectedvoidbeforeHookedMethod(MethodHookParamparam)throwsThrowable{super.beforeHookedMethod(param);//日志输出绘图开始时间戳Log.d("speedtest","DrawTimestampStart:"+System.currentTimeMillis()+"ms");}@OverrideprotectedvoidafterHookedMethod(MethodHookParamparam)throwsThrowable{super.afterHookedMethod(param);//日志输出绘图结束时间戳Log.d("speedtest","DrawTimestampEnd:"+System.currentTimeMillis()+“多发性硬化症”);}});2.4分析模块的实现该模块的核心功能是日志监控和页面耗时计算。实现监听点击事件和绘制事件的时间戳信息的输出,提取对应的事件戳,通过分析计算页面加载时间。Logcat是Android操作系统的命令工具。它的主要功能是获取应用程序的日志信息。手机通过USB连接ADBShell后,可以在命令行窗口通过“adbLogcat”命令查看。本模块的日志监控主要通过命令“adblogcat-sTag”完成,实现日志收集和Tag过滤。该模块还通过python正则匹配提取日志信息中的事件时间戳信息,计算页面加载时间。该模块的执行流程如下:启动日志监控;实时采集logcat信息,提取事件信息和时间戳信息存储到本地数据库;点击页面耗时分析计算页面耗时,计算公式为:耗时=lastDrawTimestampEndTimestamp-StartTouchTimestampTimestamp停止日志监控,结束测试;Part03测试工具应用分析为了验证工具的准确性,我们选择启动activity耗时,录屏分析获取响应时间作为实际测试的对比,测试手机型号为小米9,安卓系统版本7.1.2,录屏设备为罗技C920(录制帧率20fps),测试页面为社区公告页面,详细测试记录如下:表1不同方式页面加载消耗时间测试记录表我们对15个测试结果进行了统计分析(见图3),发现通过Hook方式获取的页面加载时间与录屏分析获取的页面加载时间基本一致,证明该工具可以用于Android上的应用响应速度测试,可以反馈用户的真实体验。图3不同方式页面加载耗时统计结果Part04结语本文设计并实现了一个基于Hook的Android应用响应时间测试工具。响应时间测试,具有测试结果准确、测试结果秒级输出的特点。除了在响应时间上使用Hook技术外,还可以用于其他性能测试,如崩溃信息获取、流量统计等,本文以响应时间测试工具为例,描述具体实现过程,旨在为其他基于Hook技术的测试工具提供基础。参考。