Android自动dump hprof文件的功能实现

要实现这个功能,必须提升权限,必须满足以下两个条件之一

1、在root的设备上运行

2、如果机子没root,需要在app的manifest文件中添加sharedUid,但是使用了这个的话,需要对apk文件进行系统签名

android:sharedUserId="android.uid.shell"


【步骤1】先准备一个工具类,用于获取进程的内存,dump hrpof文件等操作,代码如下:

**
 * 系统级的操作的工具类
 *
 */
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 list = new ArrayList();
			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;
		}

	}
}


这个里面的ShellUtils类就不给了,就是一个自己封装的方法,核心代码就是 Runtime . getRuntime (). exec ( String command )

然后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)



你可能感兴趣的:(android,自动化测试)