Android 流量優化(一):模組化流量統計
阿新 • • 發佈:2019-01-06
有個使用者說一夜間跑了幾百兆的移動流量,流量是哪裡產生的?是不是哪裡有程式碼缺陷?怎樣定位到問題? 於是想著把流量劃分模組的統計下來,以便優化App的整體健康;
如果僅統計應用總流量,類提供的介面就足以實現了;
現在我們需要分析流量的成分,一直沒有發現比較好的方法。TrafficStats類的方法setThreadStatsTag(int)可以標記執行緒,那麼這個標記什麼時候使用呢?Android monitor裡面獲取的流量資料是包含有tag的,系統肯定將tag資訊儲存在了某個地方。後來發現Android系統將放流量資料資訊儲存在檔案/proc/net/xt_qtaguid/stats 中(見原始碼),於是我們可以通過下面的方式,分析流量來源!
首先要對應用進行模組劃分,模組值Tag區間[0,
使用TrafficStats.setThreadTag(int tag)方法標記的產生流量的執行緒,引數tag是上面模組相關的tag;@See TrafficStats;
NOTE:1、一個執行緒同時只會有一個有效的tag,並且不會傳遞,依賴包啟動了新執行緒訪問網路則需要依賴方提供標記支援;2、native層socket、webview產生的流量無法使用此方法標記;
標記流量後,可以在monitor網路介面檢視流量變化,不同的tag會繪製為不同的顏色,可以先在本地分析下,使用的時候網路請求是否有冗餘;<此處應有配圖>
通過adb命令可以檢視流量內容 adb shell cat /proc/net/xt_qtaguid/stats :
搞明白欄位意思瞭解析起來也就比較容易了,直接貼程式碼
NOTE:這裡統計的流量是開機之後所有的流量統計
如果僅統計應用總流量,類提供的介面就足以實現了;
現在我們需要分析流量的成分,一直沒有發現比較好的方法。TrafficStats類的方法setThreadStatsTag(int)可以標記執行緒,那麼這個標記什麼時候使用呢?Android monitor裡面獲取的流量資料是包含有tag的,系統肯定將tag資訊儲存在了某個地方。後來發現Android系統將放流量資料資訊儲存在檔案/proc/net/xt_qtaguid/stats 中(見原始碼),於是我們可以通過下面的方式,分析流量來源!
模組劃分
首先要對應用進行模組劃分,模組值Tag區間[0,
0xFFFFFF00)。使用位表示模組與子模組之間的關係,例如0xGGPPCC00,GG一級模組、PP一級模組下的子模組,類推;
千牛是按照API介面劃分的,當然也可以按照業務場景劃分模組;
標記流量源
使用TrafficStats.setThreadTag(int tag)方法標記的產生流量的執行緒,引數tag是上面模組相關的tag;@See TrafficStats;NOTE:1、一個執行緒同時只會有一個有效的tag,並且不會傳遞,依賴包啟動了新執行緒訪問網路則需要依賴方提供標記支援;2、native層socket、webview產生的流量無法使用此方法標記;
獲取統計值
通過adb命令可以檢視流量內容 adb shell cat /proc/net/xt_qtaguid/stats :
iface:網路性質[vlan-wifi流量 lo-本地流量 rmnet0-3g/2g流量 ...]
acct_tag_hex: 執行緒標記,也就是上面我們做的標記
uid_tag_int: 應用UID,據此判斷是否是某應用統計的流量資料
cnt_set: 應用前後臺標誌位:1-前臺,0-後臺
rx_bytes: read 總接受位元組
tx_bytes: transfer總髮送位元組
搞明白欄位意思瞭解析起來也就比較容易了,直接貼程式碼
NOTE:這裡統計的流量是開機之後所有的流量統計
try {
FileReader stream = new FileReader(DEV_FILE);
BufferedReader in = new BufferedReader(stream, 500);
String line;
String[] dataStrings;
while ((line = in.readLine()) != null) {
dataStrings = line.split(" ");
if (StringUtils.equals(uid, dataStrings[3])) {
TrafficData dataTotal = new TrafficData();
TrafficData dataDiff = new TrafficData();
dataTotal.iface = dataDiff.iface = dataStrings[1];
dataTotal.moduleTag = dataDiff.moduleTag = dataStrings[2];
dataTotal.cnt_set = dataDiff.cnt_set = dataStrings[4];
dataTotal.rx_bytes = Integer.parseInt(dataStrings[5]);
dataTotal.tx_bytes = Integer.parseInt(dataStrings[6]);
//全量
if (dataTotal.rx_bytes + dataTotal.tx_bytes > 0) {
trafficDataList.add(dataTotal);
//需要根據儲存值計算增量
}
}
}
FileStoreProxy.setListValue(trafficDataList);
in.close();
stream.close();
} catch (Exception e) {
}