Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android JNI native C function call kills activity

What works: I have a c executable that runs a TUN/TAP service, and two shell scrips (to configure the "ip route" and "iptables") that run fine in terminal, all run as root.

What doesn't work: I am attempting to create an Android App to run the c executable and shell scripts after a button is pressed. I originally made it such that onClick would create a process with processBuilder as shown below:

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();             
    }
}

To the best of my knowledge this should have worked fine, but in practice mytunserv would stop working after a random period of time. mytunserv would start my TUN/TAP but then when I went to check the "ip route" after several minutes, I would see the tun/tap has stopped and disappeared. Similarly I tried runtime.exec, even though this seems to use processbuilder, and had the same issue.

I then moved onto using threads instead of processes, and this seems to work fine for the shell scripts.

...
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();             
            }
        }
    }

This seemed to work for the two shell scripts at least. I eventually gave up on this method for calling mytunserv thinking the process or thread must be getting killed by the java thread handler, which seems pretty unpredictable from my research. Instead I moved onto JNI, since this seems more suitable than hardcoding my the path to the c executables and shell scripts.

So this is my most recent issue, and what I am looking for help on.

Here is my JNI setup:

#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);
    ...
}
...

The c code above turns into 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");
    }
...

From what I can tell, the c code should be able to call other functions in the c code that are not JNIEXPORT'ed. The JNIExport is just a way to have the Java code interact with the c code, from what I imagine.

Anyway, now my issue is that in debugging or running the app on the phone once I press button1 the activity closes and goes back to my main menu activity. In Debug it says ".... DalvikVM[localhost:8602]" and in DDMS the device stays "Online". The LogCat does not output any thing to suggest that the activity exited/crashed. And upon entering the SetupTunTap activity LogCat resumes by displaying information but never outputs anything when button1 is pressed and the screen flashes black and reverts to my main menu activity. Here is the part, in the LogCat, at which the liblmytunserv is loaded:

LogCat Output:

...

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

How do I debug further? If I set a breakpoint at "myTun.runtun(ip_address);" then I can see all the variables in the Debug interface on Eclipse. If I proceed past that point, the activity disconnects and I only see the .so lib file load in the LogCat. I would guess that my JNI setup must be wrong, so any advice anywhere in my thought process would be wonderful.

Hardware: Samsung Galaxy Nexus v4.0.4 (Rooted)

Files:

  • mytunserv = c exectuable

  • setup_ip.sh = shell script

  • setup_ip1.sh = shell script

  • SetupTunTap.java

  • liblmytunserv.so (placed in /libs/armeabi, /libs/armeabi-v7a, /libs/x86)

What I need: The native "runtun" function in the C library liblmytunserv.so runs forever in a while(1) infinite loop. When the Java code calls the function (once button1 is pressed), I need the function to run forever. Shell scripts setup_ip.sh and setup_ip1.sh are run once the c executable is running. How do I get the c executable to run forever?

Let me know if you need more information, thanks for your time.

like image 992
Markus Avatar asked Nov 03 '22 19:11

Markus


1 Answers

In your JNI

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

in Activity

package android_sp_api.sample;

these need to match ;)

edit: four out of five times it's just this. also, post the java side as well, but I hope it looks like

class SetupTunTap
{
   public native int runtun(String ip_address);

/// }

so post SetupTunTap class as well\

edit2: whoopse, the edit was unneeded. it's just the package name.

like image 159
Shark Avatar answered Nov 11 '22 10:11

Shark