转帖:http://www.douban.com/note/48939107/
在android程序中执行本地进程(1.1、1.5、1.6、2.0)
2009-10-30 17:45:41
一般而言,执行本地代码是需要用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下都是有效的。