博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
libsuperuser简介
阅读量:7082 次
发布时间:2019-06-28

本文共 4636 字,大约阅读时间需要 15 分钟。

hot3.png

背景

    工作这么多年了,我常看到我身旁的程序员在弄需要访问一个文件夹启动个su的shell,chmod 777 somefolder,开放某个文件夹的读写权限。功能是实现了,但是想想,当执行root操作时,super user之类的防御软件弹出对话框警示,而用户选择了信任yourApp后,你把手机中某个文件夹的权限更改为777,然后任何其他app都可以无障碍地访问一些不该访问的文件时,你就不会觉得内疚?在很短的时间内更改某一个特定的文件的权限,访问完成后改回来,或许还可以接受,但是整个文件夹777,那也太夸张了。

其实只要在后台启动个shell,运行su,然后在这个shell上输入你的命令行就ok了。更何况已经有现成的库,有简单易懂的demo了。libsuperuser( )就是这样的一个库。

使用方式

方式一:普通的后台操作

          List<String> Shell.SH.run(String command)

List<String> Shell.SH.run(List<String> commands)

List<String> Shell.SH.run(String[] commands)

方式二:root型操作

List<String> Shell.SU.run(String command)

List<String> Shell.SU.run(List<String> commands)

List<String> Shell.SU.run(String[] commands)

方式三:

        Shell.Interactive.addCommand系列函数,支持回调函数OnCommandResultListener和OnCommandLineListener

    private void sendRootCommand() {        rootSession.addCommand(new String[] { "id", "date", "ls -l /" }, 0,                new Shell.OnCommandResultListener() {            public void onCommandResult(int commandCode, int exitCode, List
 output) {                if (exitCode < 0) {                    reportError("Error executing commands: exitCode " + exitCode);                } else {                    updateResultStatus(true, output);                    appendLineToOutput("----------");                    appendLineToOutput("ls -l /");                }            }        });

 使用时注意要在辅助线程中调用,比如AsyncTask,再比如IntentService

功能实现的核心在下面代码段

public static List
 run(String shell, String[] commands, String[] environment,            boolean wantSTDERR) {            ...            // setup our process, retrieve STDIN stream, and STDOUT/STDERR            // gobblers            Process process = Runtime.getRuntime().exec(shell, environment);            DataOutputStream STDIN = new DataOutputStream(process.getOutputStream());            StreamGobbler STDOUT = new StreamGobbler(shellUpper + "-", process.getInputStream(),                    res);            StreamGobbler STDERR = new StreamGobbler(shellUpper + "*", process.getErrorStream(),                    wantSTDERR ? res : null);            // start gobbling and write our commands to the shell            // STDOUT和STDERR是两个工作线程,用来后台进程的输出            STDOUT.start();            STDERR.start();            try {                for (String write : commands) {                    Debug.logCommand(String.format("[%s+] %s", shellUpper, write));                    STDIN.write((write + "\n").getBytes("UTF-8"));                    STDIN.flush();                }                STDIN.write("exit\n".getBytes("UTF-8"));                STDIN.flush();            } catch (IOException e) {                if (e.getMessage().contains("EPIPE")) {                    // method most horrid to catch broken pipe, in which case we                    // do nothing. the command is not a shell, the shell closed                    // STDIN, the script already contained the exit command, etc.                    // these cases we want the output instead of returning null                } else {                    // other issues we don't know how to handle, leads to                    // returning null                    throw e;                }            }            // wait for our process to finish, while we gobble away in the            // background            process.waitFor();            // make sure our threads are done gobbling, our streams are closed,            // and the process is destroyed - while the latter two shouldn't be            // needed in theory, and may even produce warnings, in "normal" Java            // they are required for guaranteed cleanup of resources, so lets be            // safe and do this on Android as well            try {                STDIN.close();            } catch (IOException e) {                // might be closed already            }            STDOUT.join();            STDERR.join();            process.destroy();            // in case of su, 255 usually indicates access denied            if (SU.isSU(shell) && (process.exitValue() == 255)) {                res = null;            }        } catch (IOException e) {            // shell probably not found            res = null;        } catch (InterruptedException e) {            // this should really be re-thrown            res = null;        }        Debug.logCommand(String.format("[%s%%] END", shell.toUpperCase(Locale.ENGLISH)));        return res;    }

结语

    我也碰到过一个同事在做应用市场app的时候,要实现“静默安装”的功能,apk下载完毕在后台静默安装app,就是也就是在su的shell中执行pm install及一些其它的辅助功能,然后捣整了好久才问我,为什么在DeviceA上行得通,在DeviceB上就不行了。我告诉他有成熟的实现方式了,回头一试,OK了。有成熟的实现方式就直接拿来用吧,或者阅读这些代码,自己提取关键代码。

转载于:https://my.oschina.net/u/1445604/blog/517272

你可能感兴趣的文章
JS设置localStorage有效期
查看>>
JSP与Servlet技术
查看>>
ErrorCode=-2147217900 表已存在.
查看>>
[MySQL]快速解决"is marked as crashed and should be repaired"故障
查看>>
System V IPC
查看>>
C语言指针转换为intptr_t类型
查看>>
ArcGIS Engine许可初始化
查看>>
寻找最长单词链
查看>>
Elasticsearch探索之路的障碍
查看>>
Head First Python 读书笔记
查看>>
TensorFlow官网无法访问
查看>>
selinux学习笔记二(selinux基础关键字介绍)
查看>>
Struts2笔记——初次框架配置
查看>>
hadoop前戏配置三:hadoop 2.2.0 重新编译为64位,个人测试成功
查看>>
图像处理之双边滤波效果(Bilateral Filtering for Gray and Color Image)
查看>>
-bash: mysql: command not found 解决办法
查看>>
VMware加载其他宿主机上的虚拟机以后,IP查不到了。如何解决?
查看>>
Postfix构建Exchange Server 2010邮件网关部署系列五:升级Exchange 2010 SP3补丁
查看>>
Exchange Server 2010 数据库故障处理实例
查看>>
Word 2003中有关分栏的常见问题集锦
查看>>