利用Fps meter 的pipe来获取android 的 Fps值

========================
前几天实习中,需要根据利用FPS Meter 来获取android 当前的FPS值。这个idea是他们给的,我需要去实现。网上有篇博客[1]对FPS meter 进行了比较深入的讲述。根据那篇博客所讲的,FPS meter 是利用native 将fps 值不断地写入到pipe当中,然后java层的服务不断地从pipe中获取。首先回顾一下pipe

Pipe

Linux 进程间的通信包括Pipe(管道),命名管道(FIFO)与信号(Signal)。so,其实Pipe就是用来进行进程间通信的。下图所示,就是Pipe的过程

管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条,管道的一端连接着一个进程的输入,管道的另外一端连着另外一个进程的输出。一个进程往管道中放入信息,另外一个进程从管道中取出信息。当管道中没有信息的时候,从管道中取出信息的进程会等待,当管道中信息满了的时候,向管道中写入信息的进程会等待,知道管道非满。当两个进程都结束的时候,管道会消失。

FPS meter 的管道使用

FPS meter程序中,他是通过一个native 进程,通过surfaceflinger 来得到 android 当前的FPS 值,让后将该值写入到pipe 当中。在FPS Meter 的java 程序中,直接读取Pipe,这样就可以运行了。
在FPS meter 的pipe 中,他是将pipe 数据作为一个4个int 型的数据的。

cat 获取pipe值。

可以将pipe当成一个文件,直接用cat 命令来读取pipe 的值。但是直接用cat 读取的时候,是可能会乱码的,cat 有时候并没有将四个32位的数的 解析成int。不过用cat 可以读取信息了。那解析我们可以自己做。再怎么着,pipe中也都是32 * 4 个的位罢了。用java 下面的代码直接就可以读取了:

String shellCommand = "adb shell cat /data/data/com.aatt.fpsm/pipe";
final long  maxBase = (int) Math.pow(2, 32);
try {
    device.executeShellCommand(shellCommand, new IShellOutputReceiver() {

        @Override
        public boolean isCancelled() {
            return false;
        }

        @Override
        public void flush() {

        }

        @Override
        public void addOutput(byte[] data,  int offset,  int length) {

            int result = 0 ;

            for(int i = offset ; i!=offset + length ; i++){
                result += data[i] *Math.pow(maxBase ,i );
            }
            System.out.println(result);
        }
    });
} catch (Exception e) {
    e.printStackTrace();
}

这样就可以将Pipe中的信息转化成int。

这样读取之后,其实还有一个小小的疑惑,虽然不影响获取值,但是还是得思考。我们自己写了一个程序去获取pipe的时候,FPS Meter 就只显示为0。认真想想Pipe 的原理就知道了。我们的程序已经将Pipe的值读取出来了。这样Pipe里面就没有任何值了,那FPS Meter 就无法从中读取值了。不过这里也有一个疑问,其实FPS meter 也是一直在读取的,优先顺序会是怎样的,从结果来看,基本是我们的程序获取了Pipe的值。或许是因为shell 级别高。但是直接用shell的时候,FPS meter 显示的值不会为0.这地方很值得思考。可惜我对这些不是很了解。


梦想在哪?