Android自動dump hprof檔案的功能實現
阿新 • • 發佈:2019-02-07
要實現這個功能,必須提升許可權,必須滿足以下兩個條件之一
1、在root的裝置上執行
2、如果機子沒root,需要在app的manifest檔案中新增sharedUid,但是使用了這個的話,需要對apk檔案進行系統簽名
android:sharedUserId="android.uid.shell"
【步驟1】先準備一個工具類,用於獲取程序的記憶體,dump hrpof檔案等操作,程式碼如下:
這個裡面的ShellUtils類就不給了,就是一個自己封裝的方法,核心程式碼就是Runtime.getRuntime().exec(String command)** * 系統級的操作的工具類 * */ public class SystemOper { private static String TAG = "SystemOper"; /** * 獲取應用所佔用的記憶體大小 * * @param pkgName 應用的包名 * @return 佔用記憶體的大小(kB),包括native heap 和 dalvik heap等,為總記憶體大小 */ public static int getProcessMemory(String pkgName) { int memoryUsed = 0; String getMemory = "dumpsys meminfo | grep " + pkgName; ShellUtils.CommandResult getMemoryResult = ShellUtils.execCommand( getMemory, false); if (getMemoryResult.successMsg.trim().length() > 0) { String str = getMemoryResult.successMsg; int end = str.indexOf(" kB:"); memoryUsed = Integer.parseInt(str.substring(0, end).trim()); Log.i(TAG, "getProcessMemory: " + memoryUsed); } return memoryUsed; } /** * dump應用的hprof檔案,為了保證資料的完整性,此步驟將耗時1分鐘 * hprof檔案存放在/sdcard/autotest/hprof路徑下 * @param pkgName 程序名稱 */ public static void getHprof(final String pkgName) { Thread dumpThread = new Thread(new Runnable() { @Override public void run() { // 1、得到程序號 String findPID = getPidByName(pkgName); if (findPID == null) { return; } File srcFile = new File("/data/local/tmp/" + pkgName + ".hprof"); Date date = new Date(); SimpleDateFormat format = new SimpleDateFormat( "yyyyMMdd_HH:mm:ss"); String time = format.format(date); File hprofFile_sdcard = new File("/sdcard/autotest/hprof/" + pkgName + "_" + time + ".hprof"); if (!hprofFile_sdcard.getParentFile().exists()) hprofFile_sdcard.getParentFile().mkdirs(); if (!hprofFile_sdcard.exists()) { try { hprofFile_sdcard.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } // 2、根據程序號dumpheap String dumpHeap = "am dumpheap " + findPID + " " + srcFile.getAbsolutePath(); ShellUtils.CommandResult dumpHeapResult = ShellUtils .execCommand(dumpHeap, false); // 3、等待dump檔案的生成 FileOperator.waitForCompleted(srcFile); // 4、將檔案拷貝到sdcard下 String cpHprof = "cp " + srcFile.getAbsolutePath() + " " + hprofFile_sdcard.getAbsolutePath(); ShellUtils.CommandResult cpHprofResult = ShellUtils .execCommand(cpHprof, false); TestReport.i(TAG, "DUMP完畢!" + cpHprofResult.errorMsg + "---" + cpHprofResult.successMsg); // 5、刪除原始檔 srcFile.delete(); } }); dumpThread.start(); } /** * 通過包名查詢pid,如果是system許可權,該方法將失效,如果程序不在,則返回null * * @param pkgName 包名 * @return pid */ public static String getPidByName(String pkgName) { String findPID = "ps | grep " + pkgName; ShellUtils.CommandResult result = ShellUtils .execCommand(findPID, false); if (result.successMsg.trim().length() > 0) { String[] strs = result.successMsg.split(" "); ArrayList<String> list = new ArrayList<String>(); for (int i = 0; i < strs.length; i++) { if (strs[i].trim().length() > 0) { list.add(strs[i]); } } return list.get(1); } else { TestReport.i(TAG, pkgName + "程序不存在!"); return null; } } }
然後dump hprof檔案的命令需要解釋下,格式為
am dumpheap pid /data/local/tmp/pkgName.hprof
這個檔案最好還是先放到tmp目錄下,不同的機子許可權不一樣,雖然理論上這個命令是可以將hprof檔案直接放到/sdcard下的,但是發現有些機子是不行的,所以為了安全起見還是放到tmp下,再拷貝出去,拷之前要確保hprof檔案已經生成完畢,
FileOperator.waitForCompleted(srcFile);
這個方法參照上一篇文章
【步驟2】自己開啟一個執行緒,不斷判斷SystemOper.getProcessMemory(youpkg)的值,如果大於你設的閾值,就呼叫SystemOper.getHprof(youpkg)