“我怎样才能跑?”;“出口”;Android上java进程中的命令?

“我怎样才能跑?”;“出口”;Android上java进程中的命令?,java,android,shell,processbuilder,Java,Android,Shell,Processbuilder,我尝试使用Java编写的应用程序在Android上运行shell脚本。我希望能够以root用户身份运行Android命令,比如am或pm,之前需要一个export LD\u LIBRARY\u PATH=/system/lib命令。不幸的是,export命令不起作用。以下是我编写的Java代码: private String readScript(String scriptPath) { String line = null; StringBuffer content = ne

我尝试使用Java编写的应用程序在Android上运行shell脚本。我希望能够以root用户身份运行Android命令,比如
am
pm
,之前需要一个
export LD\u LIBRARY\u PATH=/system/lib
命令。不幸的是,
export
命令不起作用。以下是我编写的Java代码:

private String readScript(String scriptPath) {

    String line = null;
    StringBuffer content = new StringBuffer();

    try {

        // Read the script line by line
        BufferedReader reader = new BufferedReader(new FileReader(scriptPath));
        while ((line = reader.readLine()) != null) {
            content.append(line).append('\n');
        }
        content.append("exit").append('\n');
        reader.close();

    } catch (IOException e) {

        Log.d(UpdateService.LOG_NAME, "Impossible to read script : " + e.getMessage());

    }

    return content.toString();

}

public StringBuffer runScript(String scriptPath) {

    String line = null;
    StringBuffer output = new StringBuffer();

    try {

        // Start the shell process
        ProcessBuilder pb = new ProcessBuilder("su");
        pb.redirectErrorStream(true);
        pb.directory(new File(context.getApplicationInfo().dataDir));
        pb.environment().put("LD_LIBRARY_PATH", "/system/lib");
        Process process = pb.start();

        // Execute the script
        OutputStreamWriter os = new OutputStreamWriter(process.getOutputStream());
        os.write(readScript(scriptPath));
        os.flush();
        os.close();

        // Get the output of the commands
        BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
        while ((line = in.readLine()) != null) {
            output.append(line).append('\n');
        }
        in.close();

    } catch (Exception e) {

        Log.d(UpdateService.LOG_NAME, "Error while executing " + scriptPath + " : " + e.getMessage());

    }

    return output;

}
我只是这样称呼它:

Shell = new Shell();
StringBuffer output = shell.runScript("script.sh");
我尝试运行的脚本:

export LD_LIBRARY_PATH=/system/lib
printenv
am start -W -n com.android.settings/.Settings\$InputMethodAndLanguageSettingsActivity
给我输出:

_=/system/bin/printenv
ANDROID_BOOTLOGO=1
ANDROID_PROPERTY_WORKSPACE=9,32768
LOOP_MOUNTPOINT=/mnt/obb
EXTERNAL_STORAGE=/mnt/sdcard
ANDROID_DATA=/data
RANDOM=21985
ANDROID_SOCKET_zygote=10
ASEC_MOUNTPOINT=/mnt/asec
BOOTCLASSPATH=/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/filterfw.jar
ANDROID_ROOT=/system
ANDROID_ASSETS=/system/app
PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
Segmentation fault
如您所见,使用
ProcessBuilder
environment()
方法设置的环境变量似乎没有设置,脚本中的
export
也不起作用

知道我做错了什么吗? 谢谢

编辑

根据建议,我还尝试了一个带有
exec()
的版本:

这一次,我得到了相同的输出,没有
stderr
(分段错误):

所以export
LD\u LIBRARY\u PATH=/system/lib
仍然不起作用。在我看来,
ProcessBuilder
是一种更好的启动流程的方法,因为它专门用于此流程。是这样吗

Edit2

am
pm
实际上是启动java可执行文件的包装器。我尝试实现这个包装器的C版本,以创建一个在任何情况下都可以工作的完整环境。以下是am的内容:

# Script to start "am" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/am.jar
exec app_process $base/bin com.android.commands.am.Am "$@"
这是我的C版本:

#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, const char *argv[], const char *envp[]) {
    const char **p;

    const int NUM_ARG = 3;
    const char *APP_PROCESS = "/system/bin/app_process";
    const char *BIN = "/system/bin";
    const char *AM = "com.android.commands.am.Am";

    const int NUM_ENV = 11;
    const char *ENV[] = {
        "PATH=/usr/bin:/usr/sbin:/bin:/sbin:/system/sbin:/system/bin:/system/xbin:/system/xbin/bb:/data/local/bin",
        "SHELL=/system/bin/sh",
        "MKSH=/system/bin/sh",
        "HOME=/data",
        "HOSTNAME=android",
        "USER=root",
        "LOGNAME=root",
        "TERM=xterm",
        "LD_LIBRARY_PATH=/system/lib/",
        "CLASSPATH=/system/framework/am.jar",
        NULL
    };

    int i = 0;
    char *a[argc + NUM_ARG];
    a[i] = (char *)malloc(strlen(APP_PROCESS) + 1);
    strcpy(a[i++], APP_PROCESS);
    a[i] = (char *)malloc(strlen(BIN) + 1);
    strcpy(a[i++], BIN);
    a[i] = (char *)malloc(strlen(AM) + 1);
    strcpy(a[i++], AM);
    p = argv + 1;
    for (; i < argc + NUM_ARG - 1; i++) {
        a[i] = (char *)malloc(strlen(*p) + 1);
        strcpy(a[i], *p++);
    }
    a[i] = (char *)malloc(1);
    a[i] = NULL;

    p = envp;
    int envc = 0;
    while (*p++ != NULL) envc++;

    char *v[envc + NUM_ENV];
    for (i = 0; i < envc; i++) {
        v[i] = (char *)malloc(strlen(envp[i]) + 1);
        strcpy(v[i], envp[i]);
    }
    p = ENV;
    while (*p != NULL) {
        v[i] = (char *)malloc(strlen(*p) + 1);
        strcpy(v[i++], *p++);
    }
    v[i] = (char *)malloc(1);
    v[i] = NULL;

    execve(APP_PROCESS, a, v);
    fprintf(stderr, "am: %s  error: %s\n", APP_PROCESS, strerror(errno));
    for (i = 0; i < argc + NUM_ARG; i++) {
        free(a[i]);
    }
    for (i = 0; i < envc + NUM_ENV; i++) {
        free(v[i]);
    }

    return 1;
}
但是。。。由于某些原因,它们会根据上下文进行更改或删除。例如,如果我通过ADB连接:

$ env
_=/system/xbin/env
ANDROID_BOOTLOGO=1
ANDROID_PROPERTY_WORKSPACE=9,32768
LOOP_MOUNTPOINT=/mnt/obb
PS1=$(precmd)$USER@$HOSTNAME:${PWD:-?} $ 
USER=shell
EXTERNAL_STORAGE=/mnt/sdcard
ANDROID_DATA=/data
RANDOM=22124
TERM=vt100
MKSH=/system/bin/sh
HOME=/data
LD_LIBRARY_PATH=/vendor/lib:/system/lib
ASEC_MOUNTPOINT=/mnt/asec
HOSTNAME=android
BOOTCLASSPATH=/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/filterfw.jar
ANDROID_ROOT=/system
SHELL=/system/bin/sh
ANDROID_ASSETS=/system/app
PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
如果我通过SSH连接:

$ env
_=/system/xbin/env
ANDROID_PROPERTY_WORKSPACE=9,32768
ANDROID_BOOTLOGO=1
PS1=$(precmd)$USER@$HOSTNAME:${PWD:-?} $ 
USER=shell
EXTERNAL_STORAGE=/mnt/sdcard
LOGNAME=shell
ANDROID_DATA=/data
RANDOM=4546
TERM=xterm
SHELL=/system/bin/sh
MKSH=/system/bin/sh
HOME=/data/data/com.teslacoilsw.quicksshd/home
HOSTNAME=android
BOOTCLASSPATH=/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/filterfw.jar
ANDROID_ROOT=/system
ANDROID_ASSETS=/system/app
PATH=/data/data/com.teslacoilsw.quicksshd/dropbear:/usr/bin:/usr/sbin:/bin:/sbin:/system/sbin:/system/bin:/system/xbin:/system/xbin/bb:/data/local/bin
如果我通过Java运行该命令:

$ env
_=/system/bin/printenv
ANDROID_BOOTLOGO=1
ANDROID_PROPERTY_WORKSPACE=9,32768
LOOP_MOUNTPOINT=/mnt/obb
EXTERNAL_STORAGE=/mnt/sdcard
ANDROID_DATA=/data
RANDOM=7424
ANDROID_SOCKET_zygote=10
ASEC_MOUNTPOINT=/mnt/asec
BOOTCLASSPATH=/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/filterfw.jar
ANDROID_ROOT=/system
ANDROID_ASSETS=/system/app
PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin

通过ADB,命令
am
运行良好。通过SSH,如果我运行
export LD\u LIBRARY\u PATH=/system/lib/
,它就可以工作。在Java中,它永远不起作用://

这看起来不错,但仍然不起作用(我编辑了我的问题)。谢谢你的回答!我也遇到了类似的问题,在移动设备上更新su二进制文件解决了这个问题。为了简化java的运行过程,我建议使用LibSuperUser。回到问题上来:LD_LIBRARY_PATH对linux有限制,对Android有更多限制。并不是说从am启动的任何应用程序都可能不会继承shell环境,因为am不会从shell生成进程,而是从init生成进程。所以你很可能无法继承它。我建议通过将库放在已在库搜索路径中的目录中来避免此问题。
$ env
_=/system/xbin/env
ANDROID_BOOTLOGO=1
ANDROID_PROPERTY_WORKSPACE=9,32768
LOOP_MOUNTPOINT=/mnt/obb
PS1=$(precmd)$USER@$HOSTNAME:${PWD:-?} $ 
USER=shell
EXTERNAL_STORAGE=/mnt/sdcard
ANDROID_DATA=/data
RANDOM=22124
TERM=vt100
MKSH=/system/bin/sh
HOME=/data
LD_LIBRARY_PATH=/vendor/lib:/system/lib
ASEC_MOUNTPOINT=/mnt/asec
HOSTNAME=android
BOOTCLASSPATH=/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/filterfw.jar
ANDROID_ROOT=/system
SHELL=/system/bin/sh
ANDROID_ASSETS=/system/app
PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
$ env
_=/system/xbin/env
ANDROID_PROPERTY_WORKSPACE=9,32768
ANDROID_BOOTLOGO=1
PS1=$(precmd)$USER@$HOSTNAME:${PWD:-?} $ 
USER=shell
EXTERNAL_STORAGE=/mnt/sdcard
LOGNAME=shell
ANDROID_DATA=/data
RANDOM=4546
TERM=xterm
SHELL=/system/bin/sh
MKSH=/system/bin/sh
HOME=/data/data/com.teslacoilsw.quicksshd/home
HOSTNAME=android
BOOTCLASSPATH=/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/filterfw.jar
ANDROID_ROOT=/system
ANDROID_ASSETS=/system/app
PATH=/data/data/com.teslacoilsw.quicksshd/dropbear:/usr/bin:/usr/sbin:/bin:/sbin:/system/sbin:/system/bin:/system/xbin:/system/xbin/bb:/data/local/bin
$ env
_=/system/bin/printenv
ANDROID_BOOTLOGO=1
ANDROID_PROPERTY_WORKSPACE=9,32768
LOOP_MOUNTPOINT=/mnt/obb
EXTERNAL_STORAGE=/mnt/sdcard
ANDROID_DATA=/data
RANDOM=7424
ANDROID_SOCKET_zygote=10
ASEC_MOUNTPOINT=/mnt/asec
BOOTCLASSPATH=/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/filterfw.jar
ANDROID_ROOT=/system
ANDROID_ASSETS=/system/app
PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin