2011-02-05 3 views
26

처음으로 Android 응용 프로그램을 개발 중이며 특권이 부여 된 shell 명령을 실행하기위한 "표준"방법이 있는지 궁금합니다. 나는 su을 실행 한 다음 su 프로세스의 stdin에 내 명령을 추가함으로써 한 가지 방법으로 만 수행 할 수있었습니다.안드로이드 : 안드로이드 응용 프로그램에서 루트 액세스를 얻는 방법?

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"; 

나는 포장에 대해 읽었습니다 특권 (superuser) JNI에서 호출이 가능하다? 그렇다면, 어떻게 그 일을 성취 할 수 있습니까? 그 외에도 Java에서 권한있는 명령어를 호출하는 다른 방법이 있습니까?

+2

실제로 기존 프로세스의 권한을 높이는 방법은 없으며 루트로 실행중인 새 프로세스 만 시작한다는 의미입니다. su 명령에 실행 명령이 전달 된 예제는 http://stackoverflow.com/questions/4846241/more-than-one-superuser-command-android/4846312 –

+0

을 참조하십시오. @Chris 새로운 활동/태스크/안드로이드 자바 애플 리케이션/등? –

+3

안드로이드에 엄청난 변화가 필요합니다. 일반적으로 안드로이드 자바 실행을위한 프로세스를 생성하지 않는다. 안드로이드에게 'zygote'에게 그 애플리케이션의 사용자 아이디로 포크 오프를 요청하라. 응용 프로그램 대신 핵심 작업을 수행하는 원시 실행 파일 또는 쉘 스크립트로 루트 작업을 유지하는 것이 더 간단합니다. 또는 시스템을 권한있는 시스템 서비스로 추가하십시오. 가장 좋은 방법은 유닉스 그룹을 만들어 특정 기능 (장치 파일에 대한 액세스 권한)에 액세스하고 해당 그룹에서 서비스를 실행하거나 안드로이드 권한으로 페어링하는 것입니다. –

답변

28

내가 아는 한, 루트 권한 만 사용하여 명령 줄 명령을 실행할 수 있습니다. 당신은 당신의 코드에서 루트 액세스를 래핑 내가 만든이 제네릭 클래스를 사용할 수 있습니다 http://muzikant-android.blogspot.com/2011/02/how-to-get-root-access-and-execute.html

당신이해야 할 모든이 클래스를 확장하고 루트로 실행하려는 명령을 반환 getCommandsToExecute 메소드를 오버라이드 (override)합니다.

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

귀하의 컴퓨터에 CSS 오류가있는 것 같습니다. 코드 블록. 항상 마지막 문자가 첫 번째 위치에 있습니까?! – dtrunk

+0

@dtrunk 업데이트 해 주셔서 감사합니다. 내 블로그에 오류가 수정되었습니다. – Muzikant

+0

수업을 공유해 주셔서 감사합니다. 예를 들어 매개 변수로 명령을 전달하는 것이 더 유용하다는 것을 알았습니다. boolean execute (ArrayList commands) {...} – pmont

4

제가 알고있는 가능한 해결책은 시스템으로 응용 프로그램에 서명하는 것입니다.이 응용 프로그램은 알고있는 한 루트와 정확히 같지 않습니다 : How to sign Android app with system signature?. 그러나 나는 이것이 당신이 원하는 것이 아니라고 생각합니다.

내가 한 또 다른 사항은 외부 프로세스로 실행되는 필요한 작업을 수행하는 기본 응용 프로그램을 만드는 것입니다. 그러나 파티션이 nosuid가 아니라면이 기본 응용 프로그램에 필요한 권한과 suid 비트를 제공해야합니다. 그러나 이것은 당신이 필요로하는 것이 아닙니다.

JNI를 통해 호출 된 C 코드는 동일한 프로세스에있는 것과 동일한 제한 사항을 받아야합니다.

su 바이너리를 사용할 수있는 경우 Runtime.getRuntime(). exec ("su -c reboot")과 같은 java 명령을 실행할 수 있습니다.

다른 방법은 기억이 안납니다.

관련 문제