Execute Shell Command in Android App

只要是Android開發者,一定都知道Android在SDK當中提供了一個好用的工具叫做ADB(Android Debug Bridge),它可以讓開發者透過電腦與裝置做溝通、安裝應用程式和除錯,也可以進入Unix Shell裡下其他指令。要使用ADB之前,必須先將Android裝置與電腦做連線,接著執行下列指令來確認裝置已經成功聯繫:

$ adb devices

成功連接就會出現裝置序號(Serial Number),如下圖所示。

此時,可以開始使用指令來操作系統了,最常使用的莫過於讀取Log資訊,其他像是取得系統資訊、查看目錄、搜尋檔案等等,都是時常需要使用的,下面列出一些泰勞本身常用的指令。

$ adb shell dmesg --> 核心(Kernel)Log資訊
$ adb shell logcat --> 系統和應用程式的除錯(Debug)訊息
$ adb shell dumpsys --> 提供在Services、Memory或其他系統詳細的資訊

當然也可以僅透過"adb shell"單純進入Android系統的Shell,接著你會看到終端機的開頭標示著"shell@xxxxx",通常會是裝置的某個代號。此時,不須再經由adb開頭的指令來操作了,一般Linux上常用的指令,只要Android有支援,都可以直接使用,例如:cd、cp、mv、ls、ls -la等等,如下圖所示。

簡單的講完前情提要之後,回到本篇文章的重點,要如何從應用程式的角度對系統下指令呢?其實並不難,只要使用Java提供的一些API並套入正確的指令就可以完成。有興趣想更深入研究的話,可以先詳閱以下參考資料喔!

參考資料:
Execute shell command from Android
Process - Oracle Help Center
Runtime - Oracle Help Center

廢話不多說,直接來看程式碼吧!以下範例為應用程式執行logcat指令並將包含關鍵字 "android.intent.action." 的Log紀錄篩選出來。
try { 

    //在系統裡,一般應用程式受到UID的限制,僅能查看屬於自己的Log
    //若想蒐集完整的Log必須先使用su指令切換至root身份
    Process process = Runtime.getRuntime().exec("su");
    

    //透過Outputstream將指令輸出至Shell執行
    DataOutputStream dos = new DataOutputStream(process.getOutputStream());
     

    //將欲執行的指令寫入OutPutStream
    //write方法會先將資料暫存於Buffer(緩衝區)裡面
    //"\n"是換行,相當於在Shell按下Enter讓指令執行

    dos.writeBytes("logcat -v time -d |grep 'android.intent.action.'\n");
     

    //透過getInputstream接收Shell回傳的資料,並放入BufferedReader
    BufferedReader bufferedReader =

        new BufferedReader(new InputStreamReader(process.getInputStream()));
    

    //離開root身份
    dos.writeBytes("exit\n");
    

    //flush這個方法會強制將Stream的Buffer(緩衝區)裡暫存的資料發送出去
    //在這裡的意思就是開始執行上述寫好的指令

    dos.flush(); 


} catch (IOException e) { 


    //若沒有su時該做的事

    ............
}

將Log蒐集回來之後,可以用readLine()這個方法依序將Log輸出,再看你想如何處理這些資訊。以下提供我的處理方式給大家參考。

StringBuilder mylog = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null){
     log.append(line);
     log.append("\n");
}


//轉成字串陣列
String[] splitlog;
splitlog = mylog.toString().split("\n");

如果有需要將Process回傳的資訊顯示在應用程式的畫面上,會建議將此功能寫在Service裡面,讓其與主執行序(Main Thread)分開,避免主畫面卡住。這部份可以參考泰勞放在GitHub上的完整程式碼,如下方連結所示。

GitHub:
https://github.com/Kuanlin-Chen/PIAndroid/blob/master/app/src/main/java/kkk/taiwan/kuanlin/piandroid/ServiceLog.java

留言

這個網誌中的熱門文章

Repo 實用指令

程式語言常用之符號與詞彙 - 中英文對照

什麼是 Bootloader?