1. 程式人生 > >手機效能測評之自定義獲取gfxinfo資訊

手機效能測評之自定義獲取gfxinfo資訊

概述

我們知道android系統的顯示是需要cpu和gpu的配合。cpu先將資料(如:bitmap/material等)準備好,然後交給gpu進行影象合成,然後刷到LCD上面。
Google在Jelly Bean(4.1)的推出了Project Butter(黃油計劃),讓系統的渲染和動畫都使用vsync的方式,支援高達60fps的動畫效果,換算一下也就是說繪製一幀的時間是16ms。
有了這個理論支援,我們就可以讓不同手機跑相同的2D場景,拿到每一幀的繪製時間,然後根據這個時間長短來判斷每個手機的跑2D場景的能力。

現有手段

開發者選項

進入開發者選項,然後開啟Monitoring-->Profile GPU rendering -->On Screen as bars後,會出現如下的結果

400
developer_profile.png


其中,水平的那條綠線表示的就是16ms的基準線,垂直的線則表示每幀繪製所花費的時間。根據前面的理論可以知道,超過水平綠線的幀是超過了16ms的繪製時間,如果超過的幀越多,則表示該介面會越卡頓。

gfxinfo

其實這個方式是上面方式的手動版,需要使用命令

adb shell dumpsys gfxinfo [Package Name]

來抓取graphic的資訊,但是這個命令只能抓取前128幀的資料。網上已經有很多使用和分析方法,這裡不再累述。可以檢視以下連結。
android developer
國內Falcon Pro為例的翻譯版

疑難

如果我們想做一款評測軟體,期望的動作是,使用者點選開始評測,然後軟體自己跑2D場景,一段時間後,給出一個分數來表示這段時間每幀繪製是否卡頓,以此來表示該機器2D處理能力。
但上面的二種方式無疑不合適該需求。

解決方案

只有看下gfxinfo的實現,然後寫一個程式對其實現進行包裝,獲得每幀的繪製時間後,再對這個結果進行處理。
dumpsys實現原理中的gfxinfo例項講解可以知道,如果想要在程式裡面dump資料需要dump許可權

android.Manifest.permission.DUMP

但是三方app是沒辦法拿到該許可權的。
那我們能不能直接執行許可權檢查通過後的

 mActivityManagerService.dumpGraphicsHardwareUsage(fd, pw, args);

程式碼呢?

由於該方法是私有方法,如果想呼叫只能使用反射,但是該方式又是屬於AMS的,屬於systemserver這個程序,和我們三方app不是同一個程序,也不能使用反射,所以這條路也不通。

救命稻草

沒有辦法,只有繼續看dumpGraphicsHardwareUsage的實現。
gfxinfo例項講解知道,最後正真觸發dump動作的地方是在ActivityThread的ApplicationThread類。
看到ActivityThread,是不是十分激動?!!沒錯,這個ActivityThread其實表示的就是一個應用程式的Process,我們三方應用當然也有這個ActivityThread。所以,我們可以從這裡動手!
雖然ApplicationThread是一個私有的內部類,但是因為和我們的測評程式在一個程序,所以我們可以使用反射的方法執行想要的函式.
核心程式碼如下:

Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
currentActivityThreadMethod.setAccessible(true);
ActivityThread currentActivityThread = (ActivityThread)currentActivityThreadMethod.invoke(null);


Class<?> application = Class.forName("android.app.ActivityThread$ApplicationThread");
Method method = application.getDeclaredMethod("dumpGfxInfo",new Class[]{FileDescriptor.class, String[].class});
method.setAccessible(true);
method.invoke(currentActivityThread.getApplicationThread() , fd , new String[]{"com.example.hly.fpsdetection"});

其中,fd是儲存gfxinfo資訊的fd,可以將資訊存在SD卡內上,也可以存在其他任意可讀寫位置。
com.example.hly.graphicdemo是demo程式的包名,表示dump的是當前程式的graphic資訊。當然這裡是可以替換成其他任意包名。

注意:

當我們得到gfxinfo的資訊後,還不能直接使用,需要對儲存的fd檔案進行文字解析,拿出Draw Process Execute三項的時間相加才是最後一幀繪製所花的時間。 這裡並沒有做檔案解析相關的介紹.

selinux的限制

雖然以上程式碼可以dump出gfxinfo得資訊,但是一般手機預設是沒有在開發者選項中開啟Profile GPU rendering的,所以dump出得資訊中沒有最重要的Draw Process Execute這三列的資訊。
想要有這3列資訊必須要在開發者選項中開啟Profile GPU rendering。

在selinux預設沒有開啟的手機中可以通過如下程式碼開啟Profile GPU rendering:

SystemProperties.set("debug.hwui.profile", "true");

其中"true":表示的是Profile GPU rendering中"in adb shell dumpsys gfxinfo"那一欄,不會在螢幕上顯示圖案
而"visual_bars":表示的是"Onscreen as bars"那一欄,則會在螢幕上顯示出圖案
"false" :表示"Off"那一欄,關閉profile,是預設值

但在selinux預設開啟的手機中,三方app在設定debug.hwui.profile這個屬性值的時候會被拒絕。
只能說現在手機安全係數是越來越高,被限制後唯一的解決辦法就是:

引導使用者開啟Profile GPU rendering   = =!!!

下載