如何连续执行多个根操作(批量根操作)?

时间:2014-06-19 18:23:18

标签: java android linux root batch-processing

注意:此问题不仅适用于Android开发人员。对于在Linux上执行root操作的Java开发人员来说应该是相同的。

背景

My app允许用户执行各种root操作(只能在root设备上执行的操作)。

到目前为止,每次应用程序希望执行root操作时,我都使用Runtime.getRuntime()。exec(“su”)命令打开了一个新进程。

我希望改进应用程序的工作方式,只需调用此命令一次,然后在执行此操作时写入outputStream并从inputStream读取。

执行此操作的类似应用是“Terminal emulator”。一旦你键入“su”(并授予root权限),它将允许你执行任何root操作并读取设备的任何路径。

问题

似乎只有“echo”命令有效,但任何其他命令都没有。另外,我想不出在根操作输出之间分离的好方法。

我尝试了什么

首先,为了初始化根批处理操作,我这样做了:

  process=Runtime.getRuntime().exec("su");
  _inputStreamReader=new BufferedReader(new InputStreamReader(process.getInputStream()));
  _out=process.getOutputStream();
  final String testLine=Long.toString(System.currentTimeMillis());
  _out.write(("echo "+testLine+"\n").getBytes());
  _out.flush();
  final String resultLine=_inputStreamReader.readLine();
  if(resultLine==null)
    {
    _out.write("exit \n".getBytes());
    _out.flush();
    _out.close();
    _out=null;
    _inputStreamReader.close();
    _inputStreamReader=null;
    process.waitFor();
    return false;
    }
  while(!resultLine.equals(testLine))
    resultLine=_inputStreamReader.readLine();
  return true;

上面的代码(应该)确保我有root并且我可以继续处理“_out”和“inputStreamReader”。对“echo”的调用有两个目的:完成一些虚假操作,并成为命令之间的起点和分隔符。

这里的第二个目的是假的,但对于我进一步做的每个操作,这就是我想到处理各种root操作的分离。

现在,如果我想进行另一个根操作(假设上面的工作正常),这是我想要执行的操作的一个例子:

_out.write(("find "+someFolderPath+"/* -type f\n").getBytes());
_out.flush();
final String line=_inputStreamReader.readLine();

事实是,它会卡在“readLine”部分,即使它应该返回指定路径中所有文件/文件夹的列表。

此命令使用我执行root操作的先前方式完美地工作,它也应该在这里工作。

在这些行之前使用“echo”,然后使用“readLine()”表示它仍然可用,因为我仍然会得到结果行。但是,尝试再次调用“readLine()”(在上述命令之后)仍会使其卡住。

我也尝试在“find”命令之前添加“su”(或“su - ”或“su -c”),但它没有帮助。

这是旧代码,工作正常:

  final Process p=Runtime.getRuntime().exec("su");
  final InputStream inputStream=p.getInputStream();
  final DataOutputStream os=new DataOutputStream(p.getOutputStream());
  os.writeBytes("find "+someFolderPath+"/* -type f\n");
  os.writeBytes("exit\n");
  os.flush();
  //read from the inputstream (using BufferedReader) as much as I wish, till it ends.

问题

我应该如何避免为root操作重新创建新进程?这是一个很好的方法吗?

如何修复上述代码?这有什么问题?

此外,有一种很好的方法可以使用单个“su”命令运行多个根操作,但是没有任何类型的分隔符,就像我使用过的那样(这样我可以在新的命令输出开始时区分前一个结束)。

2 个答案:

答案 0 :(得分:1)

我确信,你的find命令太慢了。您应该在不同的过程中运行它。 There是很棒的图书馆。还有manual

答案 1 :(得分:0)

好吧,即使它不是我想要的,即使我想学习如何自己做,我发现“libsuperuser”库(通过“ChainFire”)更容易

我要求的内容在此库中称为“交互模式”。

以下是我制作的示例课程,可以帮助您使用此库:

public class Root
  {
  private static final Root _instance =new Root();
  private Boolean           _hasRoot  =null;
  private Shell.Interactive _rootSession;

  public interface IGotRootListener
    {
    public void onGotRootResult(boolean hasRoot);
    }

  public static Root getInstance()
    {
    return _instance;
    }

  public boolean hasRoot()
    {
    return _hasRoot!=null&&_hasRoot;
    }

  //should be called on the UI thread
  public void getRoot(final IGotRootListener listener)
    {
    if(_hasRoot!=null&&_hasRoot)
      {
      listener.onGotRootResult(true);
      return;
      }
    final AtomicReference<Interactive> rootSessionRef=new AtomicReference<>();
    rootSessionRef.set(new Shell.Builder().useSU().setWantSTDERR(true).setWatchdogTimeout(5).setMinimalLogging(true).open(new Shell.OnCommandResultListener()
      {
        @Override
        public void onCommandResult(final int commandCode,final int exitCode,final List<String> output)
          {
          final boolean success=exitCode==Shell.OnCommandResultListener.SHELL_RUNNING;
          if(success)
            _rootSession=rootSessionRef.get();
          _hasRoot=success;
          listener.onGotRootResult(success);
          }
      }));
    }

... // TODO add functions to call commands via _rootSession.addCommand , only if got root

尽管如此,如果有人能解决我原来的问题,我很乐意了解它。