“我怎样才能跑?”;“出口”;Android上java进程中的命令?
我尝试使用Java编写的应用程序在Android上运行shell脚本。我希望能够以root用户身份运行Android命令,比如“我怎样才能跑?”;“出口”;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
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
(分段错误):
所以exportLD\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