获取FPS的几种方式
最近在实现inject+hook获取目标游戏进程的相关信息,包括系统资源占用及FPS等信息,就了解了下目前获取目标进程的FPS的方法。主要有三种:
- 通过dumpsysSurfaceFlinger | grep flips命令来获取当前系统的FPS,如果只有游戏进程在前台,也能够获取到正确的FPS信息,此方法最为简单,无需hook及inject等;
- 通过注入so到surfacelinger进程,hook eglSwapBuffers函数,记录该函数调用频率也可以获得FPS信息;
- 注入so到目标进程,并在目标进程的unity gameobject中加载脚本,记录update的调用频度来获取FPS;
第三种最为复杂,第一种最为简单,但本文着重介绍的就是第三种获取FPS的原理及实现简介。其原因为:通过在目标游戏进程注入so及cs脚本,除了可以获取FPS外,还可以实现其它更多的功能。
原理
使用inject将so文件注入到目标游戏进程后,该so调用mono相关接口,将cs编译后的dll文件加载到进程中,同时调用gameobject.AddComponent方法,此脚本就被动态加载到游戏进程中了,脚本中的update和OnGUI等都会被游戏进程调用到,只需记录update的调用频度即可获取FPS信息(当然也可以在目标游戏进程中画UI)。
步骤简介
- 准备inject进程(ATTACH到目标进程,然后在目标进程申请内存,并将一段机器指令写入目标进程,在该机器指令段内加载待注入的so文件);
- So被加载到目标进程后,调用dlsym获取mono相关接口;
- 调用mono相关接口获取到mscorlib中的System.Reflection:Assembly的class信息,并获取该class中的Load及GetType方法;
- 调用mono相关接口获取UnityEngine中GameObject的class,并获取该class中的ctor及AddComponent方法;
- 将待注入的脚本文件编译后的dll二进制内容全部读入内存code_buffer中;
- 调用3中的Load方法将code_buffer内容加载到进程;
- 加载后其会被compile;
- 获取加载后的主类的class的type信息(调用3中的GetType);
- 调用mono_object_new创建一个GameObject(使用4中获取到的class信息);
- 调用AddComponent将创建的对象加载到unity中;
至此&