什么有效:
我有一个运行TUN/TAP服务的c可执行文件,以及两个在终端运行良好的shell脚本(用于配置“ip路由”和“iptables”),它们都以root身份运行。

什么不起作用:
我试图创建一个Android应用程序,以在按下按钮后运行c可执行文件和shell脚本。最初,我这样做是为了使onClick可以使用processBuilder创建一个流程,如下所示:

final Button button1 = ...
...
public void onClick(View v) {
    String ip_address = edIPAddress.getText().toString();
    Process process;
    try {
        process = new ProcessBuilder()
            .command("/system/bin/su", "-c", "/data/tuntapserv/armeabi/mytunserv " + ip_address)
            .redirectErrorStream(true)
            .start();

        InputStream in = process.getInputStream();
        OutputStream out = process.getOutputStream();

        pOutput.append("TUN/TAP IS CONFIGURED!\n");
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

据我所知,这应该可以正常工作,但实际上,mytunserv将在随机的一段时间后停止工作。 mytunserv将启动TUN/TAP,但是几分钟后我去检查“ip route”时,我会看到tun/tap已停止并消失了。同样,我尝试了runtime.exec,即使这似乎使用了processbuilder,也遇到了同样的问题。

然后,我转而使用线程而不是进程,这对于shell脚本来说似乎很好用。
...
final Button button2 = ...
...
    public void onClick(View v) {
        sThread = new ScriptThread();
        sThread.start();
    }
...

    private class ScriptThread extends Thread {
        @Override
        public void run() {
            Process process;
            try {
                process = new ProcessBuilder()
                    .command("/system/bin/su","-c","/system/bin/sh /data/tuntapserv/armeabi/setup_ip.sh")
                    .redirectErrorStream(true)
                    .start();

                InputStream in = process.getInputStream();
                OutputStream out = process.getOutputStream();

                pOutput.append("SCRIPT FINISHED!\n");

                while(true) {
                    Thread.sleep(0);
                }

            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

这似乎至少对两个shell脚本有效。我最终放弃了这种调用mytunserv的方法,认为进程或线程必须被java线程处理程序杀死,这从我的研究看来似乎是不可预测的。相反,我转向了JNI,因为这似乎比将我的c可执行文件和shell脚本的路径硬编码为更合适。

所以这是我最近的问题,也是我正在寻求帮助的问题。

这是我的JNI设置:
#include <jni.h>
...
JNIEXPORT jint JNICALL Java_android_1sp_1api_sample_SetupTunTap_runtun(JNIEnv * env,jobject obj,jstring ip_address)
{
    jchar *ip;
    jboolean iscopy;
    ip=(*env)->GetStringUTFChars(env, ip_address, &iscopy);
    ...
    (*env)->ReleaseStringUTFChars(env, ip_address, ip);
    ...
}
...

上面的c代码变成liblmytunserv.so。
package android_sp_api.sample;
...
public class SetupTunTap extends AnotherActivity {

    static
    {
        System.loadLibrary("lmytunserv");
    }

    public native int runtun(String ip_address);
    ...

        final Button button1 = ...
    ...
    public void onClick(View v) {
        String ip_address = edIPAddress.getText().toString();

        SetupTunTap myTun = new SetupTunTap();

        myTun.runtun(ip_address);

        pOutput.append("TUN/TAP IS CONFIGURED!\n");
    }
...

据我所知,C代码应该能够调用C代码中未经JNIEXPORT处理的其他函数。根据我的想象,JNIExport只是一种使Java代码与c代码交互的方式。

无论如何,现在我的问题是,在我按下button1时,在电话上调试或运行应用程序时,该 Activity 将关闭并返回到我的主菜单 Activity 。在“调试”中显示“.... DalvikVM [localhost:8602]”,而在DDMS中,设备保持“在线”状态。 LogCat不会输出任何提示 Activity 已退出/崩溃的信息。进入SetupTunTap Activity 后,LogCat会通过显示信息来恢复,但在按button1且屏幕闪烁黑色并返回到我的主菜单 Activity 时,从不输出任何内容。这是在LogCat中加载liblmytunserv的部分:

LogCat输出:
...

07-30 16:30:19.531: D/dalvikvm(4716): Trying to load lib /data/data/android_sp_api.sample/lib/liblmytunserv.so 0x41688d20

07-30 16:30:19.531: D/dalvikvm(4716): Added shared lib /data/data/android_sp_api.sample/lib/liblmytunserv.so 0x41688d20

07-30 16:30:19.531: D/dalvikvm(4716): No JNI_OnLoad found in /data/data/android_sp_api.sample/lib/liblmytunserv.so 0x41688d20, skipping init

如何进一步调试?如果在“myTun.runtun(ip_address);”处设置断点然后我可以在Eclipse的Debug界面中看到所有变量。如果我超过了这一点, Activity 将断开连接,并且我只会在LogCat中看到.so lib文件加载。我想我的JNI设置一定是错误的,因此在我的思考过程中任何建议都是很不错的。

硬件:
三星Galaxy Nexus v4.0.4(已 Root )

文件:
  • mytunserv = c可执行
  • setup_ip.sh = shell脚本
  • setup_ip1.sh = shell脚本
  • SetupTunTap.java
  • liblmytunserv.so(放在/libs/armeabi,/libs/armeabi-v7a,/libs/x86中)

  • 我需要的:
    C库liblmytunserv.so中的 native “runtun”函数在while(1)无限循环中永久运行。当Java代码调用该函数(一旦按下button1)时,我需要该函数永久运行。一旦c可执行文件运行,将运行Shell脚本setup_ip.sh和setup_ip1.sh。如何使c可执行文件永久运行?

    如果您需要更多信息,请告诉我,谢谢您的宝贵时间。

    最佳答案

    在您的JNI中

    JNIEXPORT jint JNICALL Java_android_1sp_1api_sample_SetupTunTap_runtun(JNIEnv * env,jobject obj,jstring ip_address)
    

    Activity 中
    package android_sp_api.sample;
    

    这些需要匹配;)

    编辑:
    五分之四就是这样。另外,也要发布Java方面,但我希望它看起来像
    class SetupTunTap
    {
       public native int runtun(String ip_address);
    

    ///
    }

    因此也要发布SetupTunTap类\

    edit2:太好了,不需要编辑。它只是包名。

    10-07 19:16
    查看更多