Android 使用 shell 命令小結

一、背景說明

在 apk 開發過程中,難免遇到需要使用 apk 來執行相應的 shell 命令,本文檔就是記錄在 apk 內部如何執行 shell 命令。

二、準備知識

在使用 shell 命令之前,我們先了解一下 Android 進程基本信息。

ce

ce

如上圖,可以看到當前進程空間內,存在好多進程分別以不同的用戶權限在執行。除了常見的系統用戶,還有 wifi 用戶,nfc 用戶等,其中我們比較關注的在於 u0_axxx 。關於此部分解釋參考:關於android UID u0_axx是怎麼來的

由於在 Android 系統中,單個 APK 都是一個獨立的進程,因此,在 apk 內部執行 shell 命令,實際是以當前 apk 所在的進程用戶權限去執行對應的命令。到這裏就解釋了執行命令的權限分配問題。

二、技術說明

1、基礎用法

通過調用當前apk的運行時對象來執行 shell 命令:

  • Runtime.getRuntime().exec("ls");

運行之後,在進程中會隨機創建一個新用戶,然後以新用戶的方式來執行 shell 命令。

上述代碼有個缺點就是執行之後,無法獲取返回值。下面進行改進。

2、執行命令獲取返回值

上述命令有缺陷,現在進行改進,使其執行後可以獲取返回值。

  • public static String runCmd(String shell) {
  • String data = null;
  • try {
  • Process p = Runtime.getRuntime().exec(new String[]{"su", shell});
  • BufferedReader ie = new BufferedReader(new InputStreamReader(p.getErrorStream()));
  • BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
  • String error = null;
  • while ((error = ie.readLine()) != null
  • && !error.equals("null")) {
  • data += error + "\n";
  • }
  • String line = null;
  • while ((line = in.readLine()) != null
  • && !line.equals("null")) {
  • data += line + "\n";
  • }
  • Log.v("cmd-test = " + shell, data);
  • } catch (Exception e) {
  • e.printStackTrace();
  • }
  • return data;
  • }

3、apk 申請 root 權限

普通用法介紹完畢,還存在特殊情況,當我們需要以 root 命令來執行 shell 命令,和上面的代碼有點區別的。

首先需要 apk 申請 root 權限:

  • public static boolean RootCommand(String command) {
  • Process process = null;
  • DataOutputStream os = null;
  • try {
  • process = Runtime.getRuntime().exec("su");
  • os = new DataOutputStream(process.getOutputStream());
  • os.writeBytes(command + "\n");
  • os.writeBytes("exit\n");
  • os.flush();
  • process.waitFor();
  • } catch (Exception e) {
  • return false;
  • } finally {
  • try {
  • if (os != null) {
  • os.close();
  • }
  • process.destroy();
  • } catch (Exception e) {
  • e.printStackTrace();
  • }
  • }
  • return true;
  • }

調用方式:

  • String apkRoot = "chmod 777 " + getPackageCodePath();
  • RootCommand(apkRoot);

執行以上代碼之後,會彈出窗口提示申請 root 權限呢。允許之後當前 apk 就獲取了 root 權限了。

至於檢測是否獲取到了 root 權限,就不細說了,提供一個小思路,執行 :ll /data/data,看看返回值是什麼。

4、apk 以 root 權限執行 shell 命令

和普通命令有點區別的是,root 執行的時候需要在真正命令之前使用 su 去換到 root 用戶,然後纔開始執行 shell 命令的。

代碼如下:

  • public static void runRootCommand(String command) {
  • Process process = null;
  • DataOutputStream os = null;
  • try {
  • process = Runtime.getRuntime().exec("su");
  • os = new DataOutputStream(process.getOutputStream());
  • os.writeBytes(command + "\n");
  • os.writeBytes("exit\n");
  • os.flush();
  • process.waitFor();
  • } catch (Exception e) {
  • e.printStackTrace();
  • } finally {
  • try {
  • if (os != null) {
  • os.close();
  • }
  • process.destroy();
  • } catch (Exception e) {
  • }
  • }
  • }

以上代碼依然沒有返回值,只適合執行簡單的shell命令。

5、apk 以 root 權限執行 shell 有返回值

修改以上代碼,添加返回值:

  • public static String execRootCmd(String cmd) {
  • String result = "";
  • DataOutputStream dos = null;
  • DataInputStream dis = null;
  • try {
  • Process p = Runtime.getRuntime().exec("su");// 經過Root處理的android系統即有su命令
  • dos = new DataOutputStream(p.getOutputStream());
  • dis = new DataInputStream(p.getInputStream());
  • dos.writeBytes(cmd + "\n");
  • dos.flush();
  • dos.writeBytes("exit\n");
  • dos.flush();
  • String line = null;
  • while ((line = dis.readLine()) != null) {
  • Log.d("result", line);
  • result += line;
  • }
  • p.waitFor();
  • } catch (Exception e) {
  • e.printStackTrace();
  • } finally {
  • if (dos != null) {
  • try {
  • dos.close();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • if (dis != null) {
  • try {
  • dis.close();
  • } catch (IOException e) {
  • e.printStackTrace();
  • }
  • }
  • }
  • return result;
  • }

三、小結

apk 執行 shell 命令的場景還是比較多的,需要根據不同的需求選用合適的函數進行調用,通常來說選擇有返回值的函數進行使用即可。
在這裏可能還包含了超時命令,暫時沒做處理,有需求,再繼續分析實現吧。
以上。

發佈了52 篇原創文章 · 獲贊 61 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章