注意:此问题不仅适用于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”命令运行多个根操作,但是没有任何类型的分隔符,就像我使用过的那样(这样我可以在新的命令输出开始时区分前一个结束)。
答案 0 :(得分:1)
答案 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
尽管如此,如果有人能解决我原来的问题,我很乐意了解它。