2011-02-05 33 views
26

Tôi đang phát triển ứng dụng Android đầu tiên của mình và tôi rất tò mò nếu có bất kỳ cách "chuẩn" nào để thực thi các lệnh shell đặc quyền. Tôi chỉ có thể tìm thấy một cách để thực hiện điều đó, bằng cách thực hiện su và sau đó thêm các lệnh của tôi vào stdin của quy trình su.ANDROID: Cách truy cập root trong ứng dụng Android?

DataOutputStream pOut = new DataOutputStream(p.getOutputStream()); 
DataInputStream pIn = new DataInputStream(p.getInputStream()); 

String rv = ""; 

// su must exit before its output can be read 
pOut.writeBytes(cmd + "\nexit\n"); 
pOut.flush(); 

p.waitFor(); 

while (pIn.available() > 0) 
    rv += pIn.readLine() + "\n"; 

Tôi đã đọc về gói đặc quyền (superuser) gọi trong JNI: điều này có khả thi không? Nếu vậy, làm thế nào sẽ đi về hoàn thành nó? Ngoài ra, có cách nào khác để gọi hướng dẫn đặc quyền từ Java không?

+2

Không thực sự có bất kỳ phương tiện nào để nâng cao đặc quyền của quy trình hiện có, chỉ có nghĩa là khởi chạy một quy trình mới chạy dưới dạng gốc. Ví dụ, trong đó su được thông qua một lệnh để thực hiện, hãy xem http://stackoverflow.com/questions/4846241/more-than-one-superuser-command-android/4846312 –

+0

@Chris những gì về việc khởi chạy một Hoạt động/Nhiệm vụ/Ứng dụng java Android/etc? –

+3

Điều đó sẽ yêu cầu những thay đổi lớn đối với Android. Bạn thường không tạo ra các quy trình để thực hiện java android, thay vào đó bạn yêu cầu android yêu cầu 'zygote' đến ngã ba một lần, nó hoạt động dưới id người dùng của ứng dụng đó. Nó đơn giản hơn để giữ các tác vụ gốc như các tệp thực thi gốc hoặc các kịch bản lệnh shell thực hiện những điều quan trọng thay mặt cho ứng dụng. Hoặc thêm chúng vào hệ thống thích hợp như các dịch vụ hệ thống đặc quyền. Thông thường, cách tốt nhất là tạo nhóm unix và cấp quyền truy cập cho một khả năng cụ thể (nói quyền truy cập vào tệp thiết bị) và chạy dịch vụ trong nhóm đó hoặc ghép nối với quyền android –

Trả lời

28

Theo như tôi biết, bạn chỉ có thể chạy các lệnh dòng lệnh bằng quyền ưu tiên gốc. Bạn có thể sử dụng lớp này chung tôi đưa ra là kết thúc tốt đẹp các quyền root trong mã của bạn: http://muzikant-android.blogspot.com/2011/02/how-to-get-root-access-and-execute.html

Tất cả bạn cần làm là mở rộng lớp này và ghi đè lên các phương pháp getCommandsToExecute để trả lại các lệnh bạn muốn thực hiện như là người chủ.

public abstract class ExecuteAsRootBase 
{ 
    public static boolean canRunRootCommands() 
    { 
     boolean retval = false; 
     Process suProcess; 

     try 
     { 
     suProcess = Runtime.getRuntime().exec("su"); 

     DataOutputStream os = new DataOutputStream(suProcess.getOutputStream()); 
     DataInputStream osRes = new DataInputStream(suProcess.getInputStream()); 

     if (null != os && null != osRes) 
     { 
      // Getting the id of the current user to check if this is root 
      os.writeBytes("id\n"); 
      os.flush(); 

      String currUid = osRes.readLine(); 
      boolean exitSu = false; 
      if (null == currUid) 
      { 
       retval = false; 
       exitSu = false; 
       Log.d("ROOT", "Can't get root access or denied by user"); 
      } 
      else if (true == currUid.contains("uid=0")) 
      { 
       retval = true; 
       exitSu = true; 
       Log.d("ROOT", "Root access granted"); 
      } 
      else 
      { 
       retval = false; 
       exitSu = true; 
       Log.d("ROOT", "Root access rejected: " + currUid); 
      } 

      if (exitSu) 
      { 
       os.writeBytes("exit\n"); 
       os.flush(); 
      } 
     } 
     } 
     catch (Exception e) 
     { 
     // Can't get root ! 
     // Probably broken pipe exception on trying to write to output stream (os) after su failed, meaning that the device is not rooted 

     retval = false; 
     Log.d("ROOT", "Root access rejected [" + e.getClass().getName() + "] : " + e.getMessage()); 
     } 

     return retval; 
    } 

    public final boolean execute() 
    { 
     boolean retval = false; 

     try 
     { 
     ArrayList<String> commands = getCommandsToExecute(); 
     if (null != commands && commands.size() > 0) 
     { 
      Process suProcess = Runtime.getRuntime().exec("su"); 

      DataOutputStream os = new DataOutputStream(suProcess.getOutputStream()); 

      // Execute commands that require root access 
      for (String currCommand : commands) 
      { 
       os.writeBytes(currCommand + "\n"); 
       os.flush(); 
      } 

      os.writeBytes("exit\n"); 
      os.flush(); 

      try 
      { 
       int suProcessRetval = suProcess.waitFor(); 
       if (255 != suProcessRetval) 
       { 
        // Root access granted 
        retval = true; 
       } 
       else 
       { 
        // Root access denied 
        retval = false; 
       } 
      } 
      catch (Exception ex) 
      { 
       Log.e("ROOT", "Error executing root action", ex); 
      } 
     } 
     } 
     catch (IOException ex) 
     { 
     Log.w("ROOT", "Can't get root access", ex); 
     } 
     catch (SecurityException ex) 
     { 
     Log.w("ROOT", "Can't get root access", ex); 
     } 
     catch (Exception ex) 
     { 
     Log.w("ROOT", "Error executing internal operation", ex); 
     } 

     return retval; 
    } 
    protected abstract ArrayList<String> getCommandsToExecute(); 
} 
+0

có vẻ như có lỗi css khối mã. luôn luôn nhân vật cuối cùng là ở vị trí đầu tiên ?! – dtrunk

+0

@dtrunk Cảm ơn bạn đã cập nhật. Tôi đã sửa lỗi trên blog của mình. – Muzikant

+0

Cảm ơn bạn đã chia sẻ lớp học của mình. Tôi thấy hữu ích hơn khi chuyển các lệnh dưới dạng tham số, ví dụ: thực thi boolean (ArrayList lệnh) {...} – pmont

4

Một giải pháp có thể tôi biết là ký đơn đăng ký của bạn dưới dạng hệ thống, không chính xác như gốc như tôi biết: How to sign Android app with system signature?. Nhưng tôi cho rằng đây không phải là điều bạn muốn.

Một điều khác tôi đã làm là tạo một ứng dụng gốc thực hiện những gì cần thiết, chạy nó như là một quá trình bên ngoài. Nhưng nó là cần thiết để cung cấp cho ứng dụng bản địa này các đặc quyền bạn cần và bit suid, miễn là phân vùng không phải là nosuid. Nhưng đây không phải là những gì bạn cần hoặc là tôi giả sử.

Mã C được gọi qua JNI phải tuân theo các giới hạn giống như sống trong cùng một quy trình, tôi giả sử.

Nếu bạn có sẵn nhị phân su, bạn có thể chạy các lệnh từ java với một cái gì đó như: Runtime.getRuntime(). Exec ("su -c reboot").

Tôi không nhớ bất kỳ cách nào khác.

Các vấn đề liên quan