安卓自带实时帧率展示的2种方式详细剖析

背景

新版本的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实战开发干货,请关注下面“千里马学框架”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值