??當(dāng)你沒(méi)跨過(guò)一個(gè)問(wèn)題的時(shí)候戳气,這個(gè)問(wèn)題就會(huì)一直跟著你怨愤。
??在安卓中我們可以使用Process來(lái)執(zhí)行名命令行命令杏瞻,我們來(lái)看看如何使用符欠。
??首先是實(shí)例化嫡霞,可以通過(guò)Runtime.getRuntime().exec(cmd)獲取到Process,exec中寫入我們需要執(zhí)行的命令行即可希柿。最簡(jiǎn)單的示例如下:
public static int execCmd(String cmd) {
int result = -1;
DataOutputStream dos = null;
try {
Process p = Runtime.getRuntime().exec("su");
dos = new DataOutputStream(p.getOutputStream());
dos.writeBytes(cmd + "\n");
dos.flush();
dos.writeBytes("exit\n");
dos.flush();
p.waitFor();
result = p.exitValue();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (dos != null) {
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
}
??這里的su表示切換用戶身份诊沪,以達(dá)到root的權(quán)限,后面調(diào)用dos.writeBytes(cmd + "\n"); 執(zhí)行命令行曾撤,這里我們需要注意的方法是dos.flush(); 和p.waitFor(); 和p.exitValue(); 端姚。
??dos.flush();的作用是刷新緩沖區(qū)的信息
??p.waitFor();的作用是等待子進(jìn)程完成
??p.exitValue();是獲取命令行執(zhí)行的結(jié)果,0 表示正確執(zhí)行了挤悉。
??尤其的是p.waitFor();會(huì)導(dǎo)致線程掛起渐裸,所以我們執(zhí)行命令行的代碼一般要寫在子線程中,這里看下線程掛起是什么一個(gè)過(guò)程装悲。
?? 主進(jìn)程中調(diào)用Runtime.exec會(huì)創(chuàng)建一個(gè)子進(jìn)程昏鹃,用于執(zhí)行shell腳本。子進(jìn)程創(chuàng)建后會(huì)和主進(jìn)程分別獨(dú)立運(yùn)行诀诊。
??因?yàn)橹鬟M(jìn)程需要等待腳本執(zhí)行完成洞渤,然后對(duì)腳本返回值或輸出進(jìn)行處理,所以這里主進(jìn)程調(diào)用Process.waitfor等待子進(jìn)程完成属瓣。
?? 通過(guò)shell腳本可以看出:子進(jìn)程執(zhí)行過(guò)程就是不斷的打印信息载迄。主進(jìn)程中可以通過(guò)Process.getInputStream和Process.getErrorStream獲取并處理。
??這時(shí)候子進(jìn)程不斷向主進(jìn)程發(fā)生數(shù)據(jù)奠涌,而主進(jìn)程調(diào)用Process.waitfor后已掛起宪巨。當(dāng)前子進(jìn)程和主進(jìn)程之間的緩沖區(qū)塞滿后,子進(jìn)程不能繼續(xù)寫數(shù)據(jù)溜畅,然后也會(huì)掛起捏卓。
??這樣子進(jìn)程等待主進(jìn)程讀取數(shù)據(jù),主進(jìn)程等待子進(jìn)程結(jié)束,兩個(gè)進(jìn)程相互等待怠晴,最終導(dǎo)致死鎖遥金。
??還有一點(diǎn)就是result = p.exitValue(); 必須要寫在p.waitFor(); 的后面,因?yàn)槎卟⒉皇蔷€性執(zhí)行的蒜田,如果放在之前調(diào)用稿械,沒(méi)有等命令行執(zhí)行完成就調(diào)用,可能會(huì)報(bào)錯(cuò):process has not exited冲粤。
??為了解決線程緩沖區(qū)阻塞導(dǎo)致線程掛起美莫,我們可以不斷處理緩沖區(qū)中的數(shù)據(jù),避免阻塞梯捕,比如我們看一下在root權(quán)限下實(shí)現(xiàn)靜默升級(jí)功能的代碼厢呵,如下:
public void installAppWithRoot(String path) throws Exception {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dos = new DataOutputStream(process.getOutputStream());
dos.writeBytes("pm install -r " + path + "\n");
dos.flush();
dos.writeBytes("exit" + "\n");
dos.flush();
BufferedReader errorStream = null;
errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));
StringBuilder errorMsg = new StringBuilder();
String line;
while ((line = errorStream.readLine()) != null) {
errorMsg.append(line);
}
Log.d("apk安裝錯(cuò)誤信息", String.valueOf(errorMsg));
BufferedReader successStream = null;
StringBuilder successMsg = new StringBuilder();
successStream = new BufferedReader(new InputStreamReader(process.getInputStream()));
// 讀取命令執(zhí)行結(jié)果
while ((line = successStream.readLine()) != null) {
successMsg.append(line);
}
Log.d("apk安裝正確信息", String.valueOf(successMsg));
process.waitFor();
int result = process.exitValue();
Log.d("apk安裝返回信息", result + "");
}
??及時(shí)的處理緩沖區(qū)中的信息,打印出命令的輸出流和錯(cuò)誤信息傀顾,并保證了線程的正常執(zhí)行襟铭。