2011-08-01 17 views
11

trước hết tôi sẽ trình bày tình huống của mình. Tôi cần thực hiện lệnh "su" trong ứng dụng Android của mình và nó hoạt động tốt. Sau đó, tôi cần phải thực hiện lệnh "ls" và đọc đầu ra. Tôi đang làm nó bằng cách nhận được dòng đầu ra từ quá trình "su" và viết lệnh của tôi vào nó.Đọc đầu ra lệnh bên trong quá trình su

Và đây là câu hỏi. Làm thế nào để đọc đầu ra của quá trình "ls"? Tất cả những gì tôi có là "su" đối tượng Process. Lấy luồng đầu vào từ nó không cho gì cả, bởi vì "su" không viết gì cả. Nhưng "ls" hiện tại và tôi không biết cách truy cập thông điệp đầu ra của nó.

Tôi đã tìm kiếm nhiều trang web nhưng tôi không tìm thấy bất kỳ giải pháp nào. Có lẽ ai đó sẽ giúp tôi :)

Trân

Trả lời

23

Ok, tôi đã tìm ra một giải pháp. Nó sẽ giống như thế này:

Process p = Runtime.getRuntime().exec(new String[]{"su", "-c", "system/bin/sh"}); 
DataOutputStream stdin = new DataOutputStream(p.getOutputStream()); 
//from here all commands are executed with su permissions 
stdin.writeBytes("ls /data\n"); // \n executes the command 
InputStream stdout = p.getInputStream(); 
byte[] buffer = new byte[BUFF_LEN]; 
int read; 
String out = new String(); 
//read method will wait forever if there is nothing in the stream 
//so we need to read it in another way than while((read=stdout.read(buffer))>0) 
while(true){ 
    read = stdout.read(buffer); 
    out += new String(buffer, 0, read); 
    if(read<BUFF_LEN){ 
     //we have read everything 
     break; 
    } 
} 
//do something with the output 

Hy vọng nó sẽ rất hữu ích cho một ai đó

+4

Cuộc gọi để đọc() quầy nếu cuộc gọi hệ thống không trả lại bất cứ điều gì. Trong trường hợp đặc biệt này, "ls" nên luôn luôn trả về một cái gì đó nhưng chỉ cần ghi nhớ nó có thể gian hàng với các lệnh khác. – pmont

+1

@glodos Có cách nào để thực hiện điều này mà không chỉ định BUFF_LEN không? Đó là, đọc một dòng tại một thời điểm cho đến khi không có nhiều dòng hơn? –

+0

Xin chào, tôi đã sử dụng thành công ví dụ của bạn nhưng tôi đang nỗ lực để làm việc này trên Android Nougat. Bất cứ ai có bất kỳ ý tưởng cho điều này? – zeroprobe

4
public String ls() { 
    Class<?> execClass = Class.forName("android.os.Exec"); 
    Method createSubprocess = execClass.getMethod("createSubprocess", String.class, String.class, String.class, int[].class); 
    int[] pid = new int[1]; 
    FileDescriptor fd = (FileDescriptor)createSubprocess.invoke(null, "/system/bin/ls", "/", null, pid); 

    BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(fd))); 
    String output = ""; 
    try { 
     String line; 
     while ((line = reader.readLine()) != null) { 
      output += line + "\n"; 
     } 
    } 
    catch (IOException e) {} 
    return output; 
} 

Kiểm tra mã này đề cập ở đây:

How to run terminal command in Android application?


try { 
// Executes the command. 
Process process = Runtime.getRuntime().exec("/system/bin/ls /sdcard"); 

// Reads stdout. 
// NOTE: You can write to stdin of the command using 
//  process.getOutputStream(). 
BufferedReader reader = new BufferedReader(
     new InputStreamReader(process.getInputStream())); 
int read; 
char[] buffer = new char[4096]; 
StringBuffer output = new StringBuffer(); 
while ((read = reader.read(buffer)) > 0) { 
    output.append(buffer, 0, read); 
} 
reader.close(); 

// Waits for the command to finish. 
process.waitFor(); 

return output.toString(); 
} catch (IOException e) { 
throw new RuntimeException(e); 
} catch (InterruptedException e) { 
throw new RuntimeException(e); 
} 

Tài liệu tham khảo

this code GScript

+0

Mã này không đi làm. Không có lớp như "android.os.Exec". Tôi đã đọc rằng nó không hoạt động nữa trên Froyo và cao hơn. – glodos

+0

mmm kiểm tra khác/ –

+0

Tôi đã thử một cái gì đó như thế nhưng với "su" trước lệnh, nhưng sau đó hệ thống yêu cầu sự cho phép trên mỗi thực hiện mà bằng cách nào đó khác nhau từ trước (ví dụ danh sách thư mục khác). Tất cả những gì tôi cần làm là chỉ được phép cho lệnh "su" một lần (người dùng nhấp vào nhớ và hệ thống không bao giờ hỏi lại) và sau đó thực hiện các lệnh của tôi bên trong quá trình này và đọc kết quả của chúng.Để rõ ràng: 1. Tạo quy trình su. 2. Viết lệnh "ls" vào luồng đầu ra (ls thực hiện với sự cho phép su). 3. Đọc đầu ra "ls". Tôi không thể đạt được điểm số 3 – glodos

0

tôi sửa đổi câu trả lời chấp nhận bởi @glodos cho các vấn đề sau:

  1. các con suối đều đóng cửa, nếu không quá trình exec treo mãi mãi, trên dòng đã mở. Nếu bạn thực hiện ps trong vỏ (tức là adb shell) sau khi thực hiện nhiều lần thì bạn sẽ thấy một số quy trình su còn sống. Họ cần phải được chấm dứt đúng cách.
  2. đã thêm waitFor() để đảm bảo quá trình bị chấm dứt.
  3. Đã thêm xử lý cho read=-1, hiện tại các lệnh có số trống stdout có thể được thực thi. Trước đây chúng đã bị lỗi trên new String(buffer, 0, read)
  4. Sử dụng StringBuffer để xử lý chuỗi hiệu quả hơn.

    private String execCommand(String cmd) throws IOException, InterruptedException { 
        Process p = Runtime.getRuntime().exec(new String[]{"su", "-c", "system/bin/sh"}); 
        DataOutputStream stdout = new DataOutputStream(p.getOutputStream()); 
    
        stdout.writeBytes(cmd); 
        stdout.writeByte('\n'); 
        stdout.flush(); 
        stdout.close(); 
    
        BufferedReader stdin = new BufferedReader(new InputStreamReader(p.getInputStream())); 
        char[] buffer = new char[1024]; 
        int read; 
        StringBuffer out = new StringBuffer(); 
    
        while((read = stdin.read(buffer)) > 0) { 
         out.append(buffer, 0, read); 
        } 
        stdin.close(); 
        p.waitFor(); 
        return out.toString(); 
    } 
    

Một số các khoản tín dụng đi đến @Sherif elKhatib))