АНДРОИД: Как получить root-доступ в приложении Android? - PullRequest
28 голосов
/ 05 февраля 2011

Я занимаюсь разработкой своего первого Android приложения, и мне любопытно, есть ли какие-либо "стандартные" способы выполнения привилегированных shell команд. Мне удалось найти только один способ сделать это: выполнить su, а затем добавить свои команды к stdin процесса su.

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 ]

30 голосов
/ 18 августа 2011

Насколько я знаю, вы можете запускать команды командной строки только с правами суперпользователя.Вы можете использовать этот универсальный класс, который я создал, который обертывает корневой доступ в вашем коде: http://muzikant -android.blogspot.com / 2011/02 / как получить root-доступ-и-выполнить.html

Все, что вам нужно сделать, это расширить этот класс и переопределить метод getCommandsToExecute для возврата команд, которые вы хотите выполнить от имени пользователя root.

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();
}
5 голосов
/ 23 апреля 2011

Возможное решение, которое я знаю, - это подписать ваше приложение как системное, которое, насколько я знаю, не совпадает с root: Как подписать приложение Android системной подписью? . Но я полагаю, это не то, что вы хотели.

Еще одна вещь, которую я сделал, - это создать собственное приложение, которое делает то, что нужно, и запускает его как внешний процесс. Но необходимо дать этому собственному приложению необходимые привилегии и бит suid, если раздел не является nosuid. Но я полагаю, это не то, что вам было нужно.

Код C, вызываемый через JNI, должен быть подвержен тем же ограничениям, что и жизнь в том же процессе, я полагаю.

Если у вас есть доступный двоичный файл su, вы можете запускать команды из Java с помощью чего-то вроде: Runtime.getRuntime().exec("su -c reboot").

Я не помню другого пути.

...