refine libexec
This commit is contained in:
+2
-2
@@ -2,8 +2,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.github.shadowsocks"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="4"
|
||||
android:versionName="1.1">
|
||||
android:versionCode="5"
|
||||
android:versionName="1.1.1">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
APP_PLATFORM = anrdoid-8
|
||||
APP_PLATFORM = android-9
|
||||
|
||||
+38
-25
@@ -49,6 +49,7 @@
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static jclass class_fileDescriptor;
|
||||
static jfieldID field_fileDescriptor_descriptor;
|
||||
@@ -98,24 +99,15 @@ static int throwOutOfMemoryError(JNIEnv *env, const char *message)
|
||||
return env->ThrowNew(exClass, message);
|
||||
}
|
||||
|
||||
static int create_subprocess(const char *cmd,
|
||||
char *const argv[], char *const envp[], int* pProcessId)
|
||||
static int create_subprocess(const char *cmd, char *const argv[],
|
||||
char *const envp[], const char* scripts, int* pProcessId)
|
||||
{
|
||||
char filename[] = "/data/data/com.github.shadowsocks/defout";
|
||||
char script[] = "/data/data/com.github.shadowsocks/script";
|
||||
pid_t pid;
|
||||
int pfds[2];
|
||||
int pfds2[2];
|
||||
|
||||
if (chmod(script, 0755) < 0) {
|
||||
LOGE("error to chmod\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int defout = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
|
||||
if(defout < 0) {
|
||||
LOGE("open file error\n");
|
||||
exit(-1);
|
||||
}
|
||||
pipe(pfds);
|
||||
pipe(pfds2);
|
||||
|
||||
pid = fork();
|
||||
|
||||
@@ -126,28 +118,41 @@ static int create_subprocess(const char *cmd,
|
||||
|
||||
if(pid == 0){
|
||||
|
||||
//setsid();
|
||||
|
||||
dup2(defout, 1);
|
||||
dup2(defout, 2);
|
||||
|
||||
if (envp) {
|
||||
for (; *envp; ++envp) {
|
||||
putenv(*envp);
|
||||
}
|
||||
}
|
||||
|
||||
dup2(pfds[0], 0);
|
||||
close(pfds[1]);
|
||||
|
||||
dup2(pfds2[1], 1);
|
||||
dup2(pfds2[1], 2);
|
||||
close(pfds2[0]);
|
||||
|
||||
execv(cmd, argv);
|
||||
exit(-1);
|
||||
|
||||
fflush(NULL);
|
||||
|
||||
exit(0);
|
||||
|
||||
} else {
|
||||
*pProcessId = (int) pid;
|
||||
return defout;
|
||||
|
||||
dup2(pfds[1], 1);
|
||||
close(pfds[0]);
|
||||
|
||||
write(pfds[1], scripts, strlen(scripts)+1);
|
||||
|
||||
close(pfds2[1]);
|
||||
return pfds2[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static jobject android_os_Exec_createSubProcess(JNIEnv *env, jobject clazz,
|
||||
jstring cmd, jobjectArray args, jobjectArray envVars,
|
||||
jstring cmd, jobjectArray args, jobjectArray envVars, jstring scripts,
|
||||
jintArray processIdArray)
|
||||
{
|
||||
const jchar* str = cmd ? env->GetStringCritical(cmd, 0) : 0;
|
||||
@@ -157,6 +162,13 @@ static jobject android_os_Exec_createSubProcess(JNIEnv *env, jobject clazz,
|
||||
env->ReleaseStringCritical(cmd, str);
|
||||
}
|
||||
|
||||
const jchar* str_scripts = scripts ? env->GetStringCritical(scripts, 0) : 0;
|
||||
String8 scripts_8;
|
||||
if (str_scripts) {
|
||||
scripts_8.set(str_scripts, env->GetStringLength(scripts));
|
||||
env->ReleaseStringCritical(scripts, str_scripts);
|
||||
}
|
||||
|
||||
jsize size = args ? env->GetArrayLength(args) : 0;
|
||||
char **argv = NULL;
|
||||
String8 tmp_8;
|
||||
@@ -203,7 +215,8 @@ static jobject android_os_Exec_createSubProcess(JNIEnv *env, jobject clazz,
|
||||
}
|
||||
|
||||
int procId;
|
||||
int ptm = create_subprocess(cmd_8.string(), argv, envp, &procId);
|
||||
int ptm = create_subprocess(cmd_8.string(), argv, envp, scripts_8.string(),
|
||||
&procId);
|
||||
|
||||
if (argv) {
|
||||
for (char **tmp = argv; *tmp; ++tmp) {
|
||||
@@ -311,7 +324,7 @@ static int register_FileDescriptor(JNIEnv *env)
|
||||
static const char *classPathName = "com/github/shadowsocks/Exec";
|
||||
|
||||
static JNINativeMethod method_table[] = {
|
||||
{ "createSubprocess", "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[I)Ljava/io/FileDescriptor;",
|
||||
{ "createSubprocess", "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[I)Ljava/io/FileDescriptor;",
|
||||
(void*) android_os_Exec_createSubProcess },
|
||||
{ "waitFor", "(I)I",
|
||||
(void*) android_os_Exec_waitFor},
|
||||
|
||||
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.github.shadowsocks</groupId>
|
||||
<artifactId>shadowsocks</artifactId>
|
||||
<version>1.1</version>
|
||||
<version>1.1.1</version>
|
||||
<packaging>apk</packaging>
|
||||
<name>Shadowsocks</name>
|
||||
|
||||
|
||||
@@ -43,16 +43,18 @@ public class Exec {
|
||||
* Callers are responsible for calling Exec.close() on the returned file
|
||||
* descriptor.
|
||||
*
|
||||
* @param cmd The command to execute
|
||||
* @param args An array of arguments to the command
|
||||
* @param cmd The command to execute.
|
||||
* @param args An array of arguments to the command.
|
||||
* @param envVars An array of strings of the form "VAR=value" to be added to the
|
||||
* environment of the process
|
||||
* environment of the process.
|
||||
* @param scripts The scripts to execute.
|
||||
* @param processId A one-element array to which the process ID of the started
|
||||
* process will be written.
|
||||
* @return the file descriptor of the started process.
|
||||
* @return File descriptor
|
||||
*/
|
||||
public static native FileDescriptor createSubprocess(String cmd,
|
||||
String[] args, String[] envVars, int[] processId);
|
||||
String[] args, String[] envVars,
|
||||
String scripts, int[] processId);
|
||||
|
||||
/**
|
||||
* Send SIGHUP to a process group.
|
||||
|
||||
Regular → Executable
@@ -1,13 +1,21 @@
|
||||
package com.github.shadowsocks;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import com.google.analytics.tracking.android.EasyTracker;
|
||||
|
||||
public class ShadowsocksApplication extends Application {
|
||||
|
||||
private static String sTmpDir;
|
||||
|
||||
public static String getTmpDir() {
|
||||
return sTmpDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
EasyTracker.getInstance().setContext(this);
|
||||
sTmpDir = getCacheDir().getAbsolutePath();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,10 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Utils {
|
||||
@@ -17,51 +20,32 @@ public class Utils {
|
||||
* Internal thread used to execute scripts (as root or not).
|
||||
*/
|
||||
private static final class ScriptRunner extends Thread {
|
||||
private final File file;
|
||||
private final String script;
|
||||
private final StringBuilder res;
|
||||
private final String scripts;
|
||||
private final StringBuilder result;
|
||||
private final boolean asroot;
|
||||
public int exitcode = -1;
|
||||
// private Process exec;
|
||||
private int mProcId;
|
||||
private FileDescriptor mTermFd;
|
||||
|
||||
/**
|
||||
* Creates a new script runner.
|
||||
*
|
||||
* @param file temporary script file
|
||||
* @param script script to run
|
||||
* @param res response output
|
||||
* @param result result output
|
||||
* @param asroot if true, executes the script as root
|
||||
*/
|
||||
public ScriptRunner(File file, String script, StringBuilder res,
|
||||
public ScriptRunner(String script, StringBuilder result,
|
||||
boolean asroot) {
|
||||
this.file = file;
|
||||
this.script = script;
|
||||
this.res = res;
|
||||
this.scripts = script;
|
||||
this.result = result;
|
||||
this.asroot = asroot;
|
||||
}
|
||||
|
||||
private int createSubprocess(int[] processId, String cmd) {
|
||||
private FileDescriptor createSubprocess(int[] processId, String cmd) {
|
||||
ArrayList<String> argList = parse(cmd);
|
||||
String arg0 = argList.get(0);
|
||||
String[] args = argList.toArray(new String[1]);
|
||||
|
||||
mTermFd = Exec.createSubprocess(arg0, args, null, processId);
|
||||
return processId[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy this script runner
|
||||
*/
|
||||
@Override
|
||||
public synchronized void destroy() {
|
||||
try {
|
||||
Exec.hangupProcessGroup(mProcId);
|
||||
Exec.close(mTermFd);
|
||||
} catch (NoClassDefFoundError ignore) {
|
||||
// Nothing
|
||||
}
|
||||
return Exec.createSubprocess(arg0, args, null,
|
||||
scripts + "\nexit\n", processId);
|
||||
}
|
||||
|
||||
private ArrayList<String> parse(String cmd) {
|
||||
@@ -114,61 +98,48 @@ public class Utils {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
FileDescriptor pipe = null;
|
||||
int pid[] = new int[1];
|
||||
pid[0] = -1;
|
||||
|
||||
try {
|
||||
new File(DEFOUT_FILE).createNewFile();
|
||||
file.createNewFile();
|
||||
final String abspath = file.getAbsolutePath();
|
||||
|
||||
// TODO: Rewrite this line
|
||||
// make sure we have execution permission on the script file
|
||||
// Runtime.getRuntime().exec("chmod 755 " + abspath).waitFor();
|
||||
|
||||
// Write the script to be executed
|
||||
final OutputStreamWriter out = new OutputStreamWriter(
|
||||
new FileOutputStream(file));
|
||||
out.write("#!/system/bin/sh\n");
|
||||
out.write(script);
|
||||
if (!script.endsWith("\n"))
|
||||
out.write("\n");
|
||||
out.write("exit\n");
|
||||
out.flush();
|
||||
out.close();
|
||||
|
||||
if (this.asroot) {
|
||||
// Create the "su" request to run the script
|
||||
// exec = Runtime.getRuntime().exec(
|
||||
// root_shell + " -c " + abspath);
|
||||
|
||||
int pid[] = new int[1];
|
||||
mProcId = createSubprocess(pid, root_shell + " -c "
|
||||
+ abspath);
|
||||
pipe = createSubprocess(pid, root_shell);
|
||||
} else {
|
||||
// Create the "sh" request to run the script
|
||||
// exec = Runtime.getRuntime().exec(getShell() + " " +
|
||||
// abspath);
|
||||
|
||||
int pid[] = new int[1];
|
||||
mProcId = createSubprocess(pid, getShell() + " " + abspath);
|
||||
pipe = createSubprocess(pid, getShell());
|
||||
}
|
||||
|
||||
final InputStream stdout = new FileInputStream(DEFOUT_FILE);
|
||||
if (pipe == null) return;
|
||||
|
||||
if (pid[0] != -1) {
|
||||
Exec.waitFor(pid[0]);
|
||||
}
|
||||
|
||||
final InputStream stdout = new FileInputStream(pipe);
|
||||
final byte buf[] = new byte[8192];
|
||||
int read = 0;
|
||||
|
||||
exitcode = Exec.waitFor(mProcId);
|
||||
|
||||
// Read stdout
|
||||
while (stdout.available() > 0) {
|
||||
read = stdout.read(buf);
|
||||
if (res != null)
|
||||
res.append(new String(buf, 0, read));
|
||||
if (result != null)
|
||||
result.append(new String(buf, 0, read));
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
if (res != null)
|
||||
res.append("\n" + ex);
|
||||
Log.e(TAG, "Cannot execute command", ex);
|
||||
if (result != null)
|
||||
result.append("\n").append(ex);
|
||||
} finally {
|
||||
destroy();
|
||||
if (pipe != null) {
|
||||
Exec.close(pipe);
|
||||
}
|
||||
if (pid[0] != -1) {
|
||||
Exec.hangupProcessGroup(pid[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,8 +152,6 @@ public class Utils {
|
||||
public final static String ALTERNATIVE_ROOT = "/system/xbin/su";
|
||||
public final static String DEFAULT_IPTABLES = "/data/data/com.github.shadowsocks/iptables";
|
||||
public final static String ALTERNATIVE_IPTABLES = "/system/bin/iptables";
|
||||
public final static String SCRIPT_FILE = "/data/data/com.github.shadowsocks/script";
|
||||
public final static String DEFOUT_FILE = "/data/data/com.github.shadowsocks/defout";
|
||||
|
||||
public final static int TIME_OUT = -99;
|
||||
private static boolean initialized = false;
|
||||
@@ -281,7 +250,7 @@ public class Utils {
|
||||
public static boolean getHasRedirectSupport() {
|
||||
if (hasRedirectSupport == -1)
|
||||
initHasRedirectSupported();
|
||||
return hasRedirectSupport == 1 ? true : false;
|
||||
return hasRedirectSupport == 1;
|
||||
}
|
||||
|
||||
public static String getIptables() {
|
||||
@@ -338,7 +307,7 @@ public class Utils {
|
||||
public static boolean isRoot() {
|
||||
|
||||
if (isRoot != -1)
|
||||
return isRoot == 1 ? true : false;
|
||||
return isRoot == 1;
|
||||
|
||||
// switch between binaries
|
||||
if (new File(DEFAULT_ROOT).exists()) {
|
||||
@@ -352,7 +321,7 @@ public class Utils {
|
||||
String lines = null;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String command = "ls /\n" + "exit\n";
|
||||
String command = "ls /\n exit\n";
|
||||
|
||||
int exitcode = runScript(command, sb, 10 * 1000, true);
|
||||
|
||||
@@ -366,7 +335,7 @@ public class Utils {
|
||||
isRoot = 1;
|
||||
}
|
||||
|
||||
return isRoot == 1 ? true : false;
|
||||
return isRoot == 1;
|
||||
}
|
||||
|
||||
public static boolean runCommand(String command) {
|
||||
@@ -392,8 +361,10 @@ public class Utils {
|
||||
|
||||
public static boolean runRootCommand(String command, int timeout) {
|
||||
|
||||
if (!isRoot())
|
||||
if (!isRoot()) {
|
||||
Log.e(TAG, "Cannot get ROOT permission: " + root_shell);
|
||||
return false;
|
||||
}
|
||||
|
||||
Log.d(TAG, command);
|
||||
|
||||
@@ -402,10 +373,9 @@ public class Utils {
|
||||
return true;
|
||||
}
|
||||
|
||||
private synchronized static int runScript(String script, StringBuilder res,
|
||||
private synchronized static int runScript(String script, StringBuilder result,
|
||||
long timeout, boolean asroot) {
|
||||
final File file = new File(SCRIPT_FILE);
|
||||
final ScriptRunner runner = new ScriptRunner(file, script, res, asroot);
|
||||
final ScriptRunner runner = new ScriptRunner(script, result, asroot);
|
||||
runner.start();
|
||||
try {
|
||||
if (timeout > 0) {
|
||||
|
||||
Reference in New Issue
Block a user