背景
新版本的aosp15版本在看ViewRootImpl相关类代码时候,发现系统居然自带了各个图层的FPS相关的打印功能了,以前没有这个功能时候我们都是自己做的fps功能,今天一起来看看原生自带fps的2种方式哈。
以前马哥也给全套课程vip学员,在SurfaceFlinger代码中做过一个ui版本的实时帧率功能

这块的参考链接如下:
https://mp.weixin.qq.com/s/CvQ3-MlEHAC-Wez7pCiuIg
log打印法:
原理源码剖析:
在ViewRootImpl的draw方法中进行记录
可以看这里调用了trackFPS
/**
* Called from draw() when DEBUG_FPS is enabled
*/
private void trackFPS() {
logAndTrace("trackFPS ");
// Tracks frames per second drawn. First value in a series of draws may be bogus
// because it down not account for the intervening idle time
long nowTime = System.currentTimeMillis();
if (mFpsStartTime < 0) {
mFpsStartTime = mFpsPrevTime = nowTime;
mFpsNumFrames = 0;
} else {
//统计调用了多少次trackFPS,每次会进行增长
++mFpsNumFrames;
String thisHash = Integer.toHexString(System.identityHashCode(this));
long frameTime = nowTime - mFpsPrevTime;
long totalTime = nowTime - mFpsStartTime;
Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime);
mFpsPrevTime = nowTime;
if (totalTime > 1000) {
//用mFpsNumFrames数值计算1000ms内的数字就是fps
float fps = (float) mFpsNumFrames * 1000 / totalTime;
Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps);
mFpsStartTime = nowTime;
mFpsNumFrames = 0;
}
}
}
修改如下:

验证情况:
这里会打印出各个ViewRootImpl的实时帧率大小。

静态修改成true,会导致有大量FPS打印日志,也不适合真实的用户环境,一般都是偶尔需要查看时候通过prop来进行设置放开,改造成通过prop动态控制:
可能大家第一反应会修改成如下:
private static final boolean DEBUG_FPS =(SystemProperties.getInt("debug.fps.show", 0) == 1);
但是大家注意,这样修改后发现后续进行setprop debug.fps.show 1后,新打开的app(也就是完全一个新的进程,这种我们常规理解是新的类要重新加载)也发现没有任何的变化,永远都是保持为DEBUG_FPS false。
这里主要是因为Zygote预加载机制
Zygote进程在启动时预加载常用类
静态final变量在预加载时初始化并固定在内存中
后续应用进程fork自Zygote,继承这些"固化"的值

所以这里需要修改成如下方式:
去除final,尽量构造时候再次getprop赋值一下
private static boolean DEBUG_FPS =(SystemProperties.getInt("debug.fps.show", 0) == 1);
ViewRootImpl的构造方法中:
DEBUG_FPS = (SystemProperties.getInt("debug.fps.show", 0) == 1);
验证方式:
adb shell setprop debug.fps.show 1 (1代表打开,0代表关闭)
adb shell killall system_server

其他WMS接口方法:
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
@Override
@RequiresPermission(Manifest.permission.ACCESS_FPS_COUNTER)
public void registerTaskFpsCallback(@IntRange(from = 0) int taskId,
ITaskFpsCallback callback) {
if (mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_FPS_COUNTER)
!= PackageManager.PERMISSION_GRANTED) {
final int pid = Binder.getCallingPid();
throw new SecurityException("Access denied to process: " + pid
+ ", must have permission " + Manifest.permission.ACCESS_FPS_COUNTER);
}
if (mRoot.anyTaskForId(taskId) == null) {
throw new IllegalArgumentException("no task with taskId: " + taskId);
}
mTaskFpsCallbackController.registerListener(taskId, callback);
}
这里其实检测的是task帧率,主要统计核心是在SurfaceFlinger部分,后面SurfaceFlinger进行返回,注意这里是需要权限ACCESS_FPS_COUNTER。
使用方式案例:
public class TaskFpsCallbackTest {
private Context mContext;
private WindowManager mWindowManager;
private ActivityTaskManager mActivityTaskManager;
@Before
public void setup() {
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
mActivityTaskManager = mContext.getSystemService(ActivityTaskManager.class);
mWindowManager = mContext.getSystemService(WindowManager.class);
}
@Test
public void testRegisterAndUnregister() {
final TaskFpsCallback callback = new TaskFpsCallback() {
@Override
public void onFpsReported(float fps) {
// Ignore打印出相关的fps值
}
};
final List<ActivityManager.RunningTaskInfo> tasks = mActivityTaskManager.getTasks(1);
assertEquals(tasks.size(), 1);
mWindowManager.registerTaskFpsCallback(tasks.get(0).taskId, Runnable::run, callback);
mWindowManager.unregisterTaskFpsCallback(callback);
}
}
原文地址:
https://mp.weixin.qq.com/s/8UxEVKw_u19Wt1IlvPc9gQ
更多framework实战开发干货,请关注下面“千里马学框架”
1880

被折叠的 条评论
为什么被折叠?



