在android程序中执行本地进程(1.1、1.5、1.6、2.0)

转帖:http://www.douban.com/note/48939107/

在android程序中执行本地进程(1.1、1.5、1.6、2.0)

2009-10-30 17:45:41
在android程序中执行本地进程(1.1、1.5、1.6、2.0)_第1张图片

一般而言,执行本地代码是需要用ndk写jni lib的。在ndk发布之前的sdk 1.1时代,人们是这么越狱的:

用arm-gcc(http://www.codesourcery.com/gnu_toolchains/arm/download.html)交叉编译出本地程序,然后在java中创建进程:

try {
    // android.os.Exec is not included in android.jar so we need to use reflection.
    Class<?> execClass = Class.forName("android.os.Exec");
    Method createSubprocess = execClass.getMethod("createSubprocess",
            String.class, String.class, String.class, int[].class);
    Method waitFor = execClass.getMethod("waitFor", int.class);
    
    // Executes the command.
    // NOTE: createSubprocess() is asynchronous.
    int[] pid = new int[1];
    FileDescriptor fd = (FileDescriptor)createSubprocess.invoke(
            null, "/system/bin/ls", "/sdcard", null, pid);
    
    // Reads stdout.
    // NOTE: You can write to stdin of the command using new FileOutputStream(fd).
    FileInputStream in = new FileInputStream(fd);
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    String output = "";
    try {
        String line;
        while ((line = reader.readLine()) != null) {
            output += line + "/n";
        }
    } catch (IOException e) {
        // It seems IOException is thrown when it reaches EOF.
    }
    
    // Waits for the command to finish.
    waitFor.invoke(null, pid[0]);
    
    return output;
} catch (ClassNotFoundException e) {
    throw new RuntimeException(e.getMessage());
} catch (SecurityException e) {
    throw new RuntimeException(e.getMessage());
} catch (NoSuchMethodException e) {
    throw new RuntimeException(e.getMessage());
} catch (IllegalArgumentException e) {
    throw new RuntimeException(e.getMessage());
} catch (IllegalAccessException e) {
    throw new RuntimeException(e.getMessage());
} catch (InvocationTargetException e) {
    throw new RuntimeException(e.getMessage());
}

就这样,ls /sdcard可以成功的执行。这个方法调用了JNI函数createSubprocess,效率比较高。旧版的android版Doom就是这么越狱的。不过,android.os.Exec毕竟是未公开接口,很快就行不通了,后来的ROM甚至根本没把android.os.Exec编译进android.jar。当然,后来我们可以用ndk写lib了,不过总是有人喜欢直接执行进程的。这时网上流传出另一个更简洁的办法,继续可用:

Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
DataInputStream osRes = new DataInputStream(process.getInputStream());
for (String single : commands) {
   os.writeBytes(single + "/n");
   os.flush();
   res.add(osRes.readLine());
}
os.writeBytes("exit/n");
os.flush();
process.waitFor();

这个方法在1.1时还是可用的,但从1.5开始,用户权限代码陆续实现了,普通程序不能再执行su命令,只能这么干了:

public String exec(String command) {
	StringBuffer output = new StringBuffer();
	Log.d("exec", command);
	try {
		Process process = Runtime.getRuntime().exec(command);
		DataInputStream stdout = new DataInputStream(process.getInputStream());
		String line;
		while ((line = stdout.readLine()) != null) {
			output.append(line).append('/n');
		}
		process.waitFor();
	} catch (Exception e) {
		output.append('/n').append(e.toString());
	}
	return output.toString();
}

经过验证,此方法在1.6、2.0下都是有效的。

你可能感兴趣的:(android,String,command,jni,null,output)