简体   繁体   English

执行 shell 命令

[英]Executing shell commands

I'm having some trouble getting my app to execute that command, it asks for root access but does not run the kill $(pidof cameraserver) part.我在让我的应用程序执行该命令时遇到了一些麻烦,它要求 root 访问权限但不运行 kill $(pidof cameraserver) 部分。

If I run kill $(pidof cameraserver) from the terminal on my phone it works, but not when I hit the button on my app.如果我从手机上的终端运行 kill $(pidof cameraserver) 它可以工作,但当我点击我的应用程序上的按钮时就不行了。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button action = findViewById(R.id.buttonAction);

    action.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            try {
                Process process;
                Process secondProcess;
                process = Runtime.getRuntime().exec("su kill $pidof(cameraserver)");
                BufferedReader in = new BufferedReader
                        (new InputStreamReader(process.getInputStream()));
            }
            catch (IOException e){
                e.printStackTrace();
            }
        }
    });

}

I doubt that $(pidof cameraserver) will be expanded by the exec() method.我怀疑$(pidof cameraserver)是否会被exec()方法扩展。 This is a shell feature.这是 shell 功能。 It works in the terminal, because that's a shell.它在终端中工作,因为那是 shell。 You would have to exec pidof cameraserver first and use the result of that for a second call to exec.您必须先执行pidof cameraserver并将其结果用于第二次调用 exec。

I also believe, that you can not use the single argument overload of exec this way.我也相信,你不能以这种方式使用 exec 的单参数重载。 You would rather have to provide a string array that contains the command and its parameter as separate array items.您宁愿提供一个字符串数组,其中包含作为单独数组项的命令及其参数。

You're confused.你很困惑。 Your post title is Executing shell commands , and yet what you're doing is.. not that.您的帖子标题是Executing shell commands ,但您正在做的是……不是那样的。

Runtime.exec does not run shell commands . Runtime.exec运行 shell 命令

It runs executables, with its own extremely crappy shell-like behaviour you should not rely on.它运行可执行文件,具有你不应该依赖的极其糟糕的类似 shell 的行为。

Just su , in bash, will apply aliases, check if it's a bash built-in, and if none of those apply, scans the PATH.只需su ,在 bash 中,将应用别名,检查它是否是内置的 bash,如果这些都不适用,则扫描 PATH。 Runtime.exec does almost none of those things (it kinda scans PATH, but don't rely on that). Runtime.exec 几乎不做这些事情(它有点扫描 PATH,但不要依赖它)。 bash will expand ${pid} , * , and many other things. bash 将扩展${pid}*和许多其他内容。 Runtime.exec doesn't do any of these things . Runtime.exec 不做任何这些事情

For starters, take Runtime.getRuntime().exec and put it on your verboten list.对于初学者,请使用Runtime.getRuntime().exec并将其放在您的禁止列表中。 You should never ever call this method.你永远不应该调用这个方法。 Let it join Thread.stop and all those silent char-to-byte conversion methods that don't include a charset.让它加入Thread.stop和所有那些不包含字符集的静默字符到字节转换方法。

The right way to do process control is to use ProcessBuilder .进行过程控制的正确方法是使用ProcessBuilder This makes a lot more clear what is happening:这使发生的事情更加清楚:

Java will run the exact application you provide (so, don't do su , do /bin/su ), and pass arguments verbatim with absolutely no parsing whatsoever. Java 将运行您提供的确切应用程序(因此,不要执行su ,执行/bin/su ),并逐字传递 arguments ,绝对不进行任何解析。 With the exec method you use, java will try to apply quote separation and otherwise treats spaces as separators, and does nothing more.使用您使用的 exec 方法,java 将尝试应用引号分隔,否则将空格视为分隔符,仅此而已。 This confusing mix of some bashisms (such as splitting your string on spaces and then treating each part as an argument) and lack of bashisms (not applying *.txt, or ${var} and friends, or supporting any of the built-ins) is just going to lead to a lot of confusion.这种混淆混合了一些 bashism(例如将字符串拆分为空格,然后将每个部分视为参数)和缺乏 bashism(不应用 *.txt,或 ${var} 和朋友,或支持任何内置函数) 只会导致很多混乱。

You have two general options:您有两个通用选项:

  1. Realize java just tells the OS to fire app A with argslist B with no processing whatsoever, and 'bash' is not built into the OS. Realize java 只是告诉操作系统使用 argslist B 启动应用程序 A 而不进行任何处理,并且操作系统中没有内置“bash”。 There is simply no way to do any of these things directly, you have to program them.根本没有办法直接做这些事情,你必须对它们进行编程。 Whatever pidof does, you'd have to program it in java.无论 pidof 做什么,您都必须在 java 中对其进行编程。

  2. Start bash, not su.启动bash,不是su。 Then tell bash to run this command.然后告诉 bash 运行这个命令。

option 2 is possibly easier here:选项2在这里可能更容易:

ProcessBuilder pb = new ProcessBuilder();
pb.command("/bin/bash", "-c", "su kill $pidof(cameraserver)");
Process p = pb.start();

Then you're stuck trying to deal with the fact you're calling su , which goes out of its way to stop you from doing this.然后你被困在试图处理你调用su的事实,这会阻止你这样做。 Having a script just casually pick up root rights is something that is just going to lead to a ton of security issues.让脚本随便获取根权限会导致大量安全问题。

Find another way.寻找另一种方式。 For example, make a shell script that runs this command, then use some linux knowhow to give this shell SUID rights (so that it automatically and silently is run with the rights of the owner), then make it owned by root, and then use processbuilder to exec "/bin/bash" , "-c" , "/path/to/that/script" .例如,制作一个运行此命令的 shell 脚本,然后使用一些 linux 知识给此 shell 以 SUID 权限运行(然后使用它的所有者),然后自动以 SUID 权限拥有它并静默运行processbuilder 执行"/bin/bash""-c""/path/to/that/script" This has a chance of being safe: That shell can only be written to by root (make sure of that,), and thus you have now decided, as operator of the hardware you run this on.这有可能是安全的:shell 只能由 root 写入(确保这一点),因此您现在已经决定,作为运行它的硬件的操作员。 that this specific job is acceptable even for non-root users to run.即使非 root 用户也可以运行此特定作业。

NB: If you've configured your su to just let this happen without asking for passwords, go back.注意:如果您已将 su 配置为让这种情况发生而不要求输入密码,则返回 go。 Undo that mistake.撤消那个错误。 Keep your system safe.确保您的系统安全。 root access is hidden behind a few doors for a reason.出于某种原因,root 访问权限隐藏在几扇门后面。 Stop replacing the locks on your safe with paper and sticks.停止用纸和棍子替换保险箱上的锁。

I finally fixed the issue, I have my phone rooted with Magisk so all i had to do was use their 'su' file, I'm new to Java and android development so i don't really know how to explain myself in proper terms but here's the code:我终于解决了这个问题,我的手机植根于 Magisk,所以我所要做的就是使用他们的“su”文件,我是 Java 和 android 开发的新手,所以我真的不知道如何用适当的术语解释自己但这是代码:

ProcessBuilder pb = new ProcessBuilder();
                pb.command("/sbin/su", "-c","pkill cameraserver");
                Process p = pb.start();

This limits the user to use Magisk, but since this is for personal use it wont matter much.这限制了用户使用 Magisk,但由于这是供个人使用的,所以没有多大关系。

Thanks to EricSchaefer and rzwitserloot for their knowledge and help.感谢 EricSchaefer 和 rzwitserloot 提供的知识和帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM