diff options
author | Tobias Brunner <tobias@strongswan.org> | 2012-10-10 14:14:30 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2012-10-16 14:16:17 +0200 |
commit | ef3d1a1ba95692b354e07d256fddce892382e24e (patch) | |
tree | b5a5085206e6886ca01a4d7f0be07f9b40ba4deb | |
parent | 38bbca587fab96550005fc06eaabecd2d4dd0507 (diff) | |
download | strongswan-ef3d1a1ba95692b354e07d256fddce892382e24e.tar.bz2 strongswan-ef3d1a1ba95692b354e07d256fddce892382e24e.tar.xz |
android: Register NetworkManager as BroadcastReceiver and relay events via JNI
5 files changed, 184 insertions, 8 deletions
diff --git a/src/frontends/android/AndroidManifest.xml b/src/frontends/android/AndroidManifest.xml index f0ed02ff3..4655cd7fc 100644 --- a/src/frontends/android/AndroidManifest.xml +++ b/src/frontends/android/AndroidManifest.xml @@ -23,6 +23,7 @@ <uses-sdk android:minSdkVersion="14" /> <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <application android:icon="@drawable/ic_launcher" diff --git a/src/frontends/android/jni/libandroidbridge/charonservice.c b/src/frontends/android/jni/libandroidbridge/charonservice.c index 96a4da8f3..591ca90ec 100644 --- a/src/frontends/android/jni/libandroidbridge/charonservice.c +++ b/src/frontends/android/jni/libandroidbridge/charonservice.c @@ -414,7 +414,7 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder) .attr = android_attr_create(), .creds = android_creds_create(), .builder = vpnservice_builder_create(builder), - .network_manager = network_manager_create(), + .network_manager = network_manager_create(service), .vpn_service = (*env)->NewGlobalRef(env, service), ); charonservice = &this->public; diff --git a/src/frontends/android/jni/libandroidbridge/kernel/network_manager.c b/src/frontends/android/jni/libandroidbridge/kernel/network_manager.c index e7bcf1365..9c97fbb14 100644 --- a/src/frontends/android/jni/libandroidbridge/kernel/network_manager.c +++ b/src/frontends/android/jni/libandroidbridge/kernel/network_manager.c @@ -15,7 +15,9 @@ #include "network_manager.h" #include "../android_jni.h" +#include "../charonservice.h" #include <debug.h> +#include <threading/mutex.h> typedef struct private_network_manager_t private_network_manager_t; @@ -35,6 +37,19 @@ struct private_network_manager_t { * Java class for NetworkManager */ jclass cls; + + /** + * Registered callback + */ + struct { + connectivity_cb_t cb; + void *data; + } connectivity_cb; + + /** + * Mutex to access callback + */ + mutex_t *mutex; }; METHOD(network_manager_t, get_local_address, host_t*, @@ -70,11 +85,99 @@ failed: return NULL; } +JNI_METHOD(NetworkManager, networkChanged, void, + bool disconnected) +{ + private_network_manager_t *nm; + + nm = (private_network_manager_t*)charonservice->get_network_manager( + charonservice); + nm->mutex->lock(nm->mutex); + if (nm->connectivity_cb.cb) + { + nm->connectivity_cb.cb(nm->connectivity_cb.data, disconnected); + } + nm->mutex->unlock(nm->mutex); +} + +METHOD(network_manager_t, add_connectivity_cb, void, + private_network_manager_t *this, connectivity_cb_t cb, void *data) +{ + this->mutex->lock(this->mutex); + if (!this->connectivity_cb.cb) + { + JNIEnv *env; + jmethodID method_id; + + androidjni_attach_thread(&env); + method_id = (*env)->GetMethodID(env, this->cls, "Register", "()V"); + if (!method_id) + { + androidjni_exception_occurred(env); + } + else + { + (*env)->CallVoidMethod(env, this->obj, method_id); + if (!androidjni_exception_occurred(env)) + { + this->connectivity_cb.cb = cb; + this->connectivity_cb.data = data; + } + androidjni_detach_thread(); + } + } + this->mutex->unlock(this->mutex); +} + +/** + * Unregister the NetworkManager via JNI. + * + * this->mutex has to be locked + */ +static void unregister_network_manager(private_network_manager_t *this) +{ + JNIEnv *env; + jmethodID method_id; + + androidjni_attach_thread(&env); + method_id = (*env)->GetMethodID(env, this->cls, "Unregister", "()V"); + if (!method_id) + { + androidjni_exception_occurred(env); + } + else + { + (*env)->CallVoidMethod(env, this->obj, method_id); + androidjni_exception_occurred(env); + } + androidjni_detach_thread(); +} + +METHOD(network_manager_t, remove_connectivity_cb, void, + private_network_manager_t *this, connectivity_cb_t cb) +{ + this->mutex->lock(this->mutex); + if (this->connectivity_cb.cb == cb) + { + this->connectivity_cb.cb = NULL; + unregister_network_manager(this); + } + this->mutex->unlock(this->mutex); +} + METHOD(network_manager_t, destroy, void, private_network_manager_t *this) { JNIEnv *env; + this->mutex->lock(this->mutex); + if (this->connectivity_cb.cb) + { + this->connectivity_cb.cb = NULL; + unregister_network_manager(this); + } + this->mutex->unlock(this->mutex); + androidjni_attach_thread(&env); if (this->obj) { @@ -85,13 +188,14 @@ METHOD(network_manager_t, destroy, void, (*env)->DeleteGlobalRef(env, this->cls); } androidjni_detach_thread(); + this->mutex->destroy(this->mutex); free(this); } /* * Described in header. */ -network_manager_t *network_manager_create() +network_manager_t *network_manager_create(jobject context) { private_network_manager_t *this; JNIEnv *env; @@ -102,8 +206,11 @@ network_manager_t *network_manager_create() INIT(this, .public = { .get_local_address = _get_local_address, + .add_connectivity_cb = _add_connectivity_cb, + .remove_connectivity_cb = _remove_connectivity_cb, .destroy = _destroy, }, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), ); androidjni_attach_thread(&env); @@ -114,12 +221,12 @@ network_manager_t *network_manager_create() } this->cls = (*env)->NewGlobalRef(env, cls); method_id = (*env)->GetMethodID(env, cls, "<init>", - "()V"); + "(Landroid/content/Context;)V"); if (!method_id) { goto failed; } - obj = (*env)->NewObject(env, cls, method_id); + obj = (*env)->NewObject(env, cls, method_id, context); if (!obj) { goto failed; diff --git a/src/frontends/android/jni/libandroidbridge/kernel/network_manager.h b/src/frontends/android/jni/libandroidbridge/kernel/network_manager.h index cb0da7fa2..634816405 100644 --- a/src/frontends/android/jni/libandroidbridge/kernel/network_manager.h +++ b/src/frontends/android/jni/libandroidbridge/kernel/network_manager.h @@ -29,7 +29,19 @@ typedef struct network_manager_t network_manager_t; /** - * NetworkManager, used to retrieve local IP addresses. + * Callback called if connectivity changes somehow. + * + * Implementation should be quick as the call is made by the Java apps main + * thread. + * + * @param data data supplied during registration + * @param disconnected TRUE if currently disconnected + */ +typedef void (*connectivity_cb_t)(void *data, bool disconnected); + +/** + * NetworkManager, used to listen for network changes and retrieve local IP + * addresses. * * Communicates with NetworkManager via JNI */ @@ -44,6 +56,25 @@ struct network_manager_t { host_t *(*get_local_address)(network_manager_t *this, bool ipv4); /** + * Register a callback that is called if connectivity changes + * + * @note Only the first registered callback is currently used + * + * @param cb callback to register + * @param data data provided to callback + */ + void (*add_connectivity_cb)(network_manager_t *this, connectivity_cb_t cb, + void *data); + + /** + * Unregister a previously registered callback for connectivity changes + * + * @param cb previously registered callback + */ + void (*remove_connectivity_cb)(network_manager_t *this, + connectivity_cb_t cb); + + /** * Destroy a network_manager_t instance */ void (*destroy)(network_manager_t *this); @@ -52,8 +83,9 @@ struct network_manager_t { /** * Create a network_manager_t instance * + * @param context Context object * @return network_manager_t instance */ -network_manager_t *network_manager_create(); +network_manager_t *network_manager_create(jobject context); #endif /** NETWORK_MANAGER_H_ @}*/ diff --git a/src/frontends/android/src/org/strongswan/android/logic/NetworkManager.java b/src/frontends/android/src/org/strongswan/android/logic/NetworkManager.java index d9ed49b34..160865fb7 100644 --- a/src/frontends/android/src/org/strongswan/android/logic/NetworkManager.java +++ b/src/frontends/android/src/org/strongswan/android/logic/NetworkManager.java @@ -22,12 +22,48 @@ import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; -public class NetworkManager +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +public class NetworkManager extends BroadcastReceiver { - public NetworkManager() + private final Context mContext; + private boolean mRegistered; + + public NetworkManager(Context context) + { + mContext = context; + } + + public void Register() + { + mContext.registerReceiver(this, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); + } + + public void Unregister() { + mContext.unregisterReceiver(this); } + @Override + public void onReceive(Context context, Intent intent) + { + ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo info = cm.getActiveNetworkInfo(); + networkChanged(info == null || !info.isConnected()); + } + + /** + * Notify the native parts about a network change + * + * @param disconnected true if no connection is available at the moment + */ + public native void networkChanged(boolean disconnected); + /** * Function that retrieves a local address of the given family. * |