wakelock.c 4.37 KB
Newer Older
1 2
#include "wakelock_internal.h"
#include "belle-sip/utils.h"
3
#include <pthread.h>
4

5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
struct _WakeLock {
	JavaVM *jvm;
	jobject powerManager;
	pthread_key_t jniEnvKey;
	jint PARTIAL_WAKE_LOCK;
	jmethodID newWakeLockID;
	jmethodID acquireID;
	jmethodID releaseID;
};

typedef struct _WakeLock WakeLock;

static WakeLock ctx = {
	.jvm = NULL,
	.powerManager = NULL
};
21

22 23 24 25
static JNIEnv *get_jni_env(void);
static void jni_key_cleanup(void *data);

void bellesip_wake_lock_init(JNIEnv *env, jobject pm) {
26 27 28 29 30 31 32 33 34 35 36 37 38 39
	if(ctx.jvm == NULL) {
		(*env)->GetJavaVM(env, &ctx.jvm);
		ctx.powerManager = (*env)->NewGlobalRef(env, pm);
		pthread_key_create(&ctx.jniEnvKey, jni_key_cleanup);

		jclass powerManagerClass = (*env)->FindClass(env, "android/os/PowerManager");
		jclass wakeLockClass = (*env)->FindClass(env, "android/os/PowerManager$WakeLock");
		jfieldID fieldID = (*env)->GetStaticFieldID(env, powerManagerClass, "PARTIAL_WAKE_LOCK", "I");

		ctx.PARTIAL_WAKE_LOCK = (*env)->GetStaticIntField(env, powerManagerClass, fieldID);
		ctx.newWakeLockID = (*env)->GetMethodID(env, powerManagerClass, "newWakeLock", "(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;");
		ctx.acquireID = (*env)->GetMethodID(env, wakeLockClass, "acquire", "()V");
		ctx.releaseID = (*env)->GetMethodID(env, wakeLockClass, "release", "()V");

40
		belle_sip_message("bellesip_wake_lock_init(): initialization succeed");
41
	} else {
François Grisez's avatar
François Grisez committed
42
		belle_sip_warning("bellesip_wake_lock_init(): the wakelock system has already been initialized");
43 44 45
	}
}

46
void bellesip_wake_lock_uninit(JNIEnv *env) {
47 48 49 50
	ctx.jvm = NULL;
	if(ctx.powerManager != NULL) {
		(*env)->DeleteGlobalRef(env, ctx.powerManager);
		ctx.powerManager = NULL;
51 52 53
	}
}

François Grisez's avatar
François Grisez committed
54 55 56 57 58
/**
 * @brief Callback called when a thread terminates it-self.
 * It detaches the thread from the JVM.
 * @param data Unused.
 */
59 60
static void jni_key_cleanup(void *data) {
	belle_sip_message("Thread end. Cleanup wake lock jni environment");
61
	JNIEnv *env = pthread_getspecific(ctx.jniEnvKey);
62
	if(env != NULL) {
63 64 65
		if(ctx.jvm != NULL) {
			(*ctx.jvm)->DetachCurrentThread(ctx.jvm);
			pthread_setspecific(ctx.jniEnvKey, NULL);
66 67 68 69 70 71
		} else {
			belle_sip_fatal("Wake lock cleanup. No JVM found");
		}
	}
}

François Grisez's avatar
François Grisez committed
72 73 74 75 76 77 78
/**
 * @brief Get a JNI environment.
 * Get a JNI by attaching the current thread
 * to the internaly stored JVM. That function can be safely
 * called several times.
 * @return JNI environement pointer. NULL if the function fails.
 */
79 80
static JNIEnv *get_jni_env(void) {
	JNIEnv *jenv = NULL;
81 82
	if(ctx.jvm != NULL) {
		jenv = pthread_getspecific(ctx.jniEnvKey);
83
		if(jenv == NULL) {
84 85
			if((*ctx.jvm)->AttachCurrentThread(ctx.jvm, &jenv, NULL) == JNI_OK) {
				pthread_setspecific(ctx.jniEnvKey, jenv);
86 87 88 89 90 91 92 93 94 95 96 97
				belle_sip_message("get_jni_env(): thread successfuly attached");
			} else {
				belle_sip_fatal("get_jni_env(): thread could not be attached to the JVM");
				jenv = NULL;
			}
		}
	} else {
		belle_sip_error("get_jni_env(): no JVM found");
	}
	return jenv;
}

98
unsigned long wake_lock_acquire(const char *tag) {
99
	if(ctx.jvm != NULL && ctx.powerManager != NULL) {
100
		JNIEnv *env;
101
		if((env = get_jni_env())) {
102
			jstring tagString = (*env)->NewStringUTF(env, tag);
103
			jobject lock = (*env)->CallObjectMethod(env, ctx.powerManager, ctx.newWakeLockID, ctx.PARTIAL_WAKE_LOCK, tagString);
104
			(*env)->DeleteLocalRef(env, tagString);
105 106 107 108 109 110 111 112
			if(lock != NULL) {
				(*env)->CallVoidMethod(env, lock, ctx.acquireID);
				lock = (*env)->NewGlobalRef(env, lock);
				belle_sip_message("bellesip_wake_lock_acquire(): Android wake lock acquired [ref=%p]", (void *)lock);
				return (unsigned long)lock;
			} else {
				belle_sip_message("wake_lock_acquire(): wake lock creation failed");
			}
113
		} else {
François Grisez's avatar
François Grisez committed
114
			belle_sip_error("bellesip_wake_lock_acquire(): cannot attach current thread to the JVM");
115 116
		}
	} else {
117
		belle_sip_error("bellesip_wake_lock_acquire(): cannot acquire wake lock. No JVM found");
118 119 120 121
	}
	return 0;
}

122

123
void wake_lock_release(unsigned long id) {
124
	if(ctx.jvm != NULL && ctx.powerManager != NULL) {
125 126 127
		if(id != 0) {
			jobject lock = (jobject)id;
			JNIEnv *env;
128
			if((env = get_jni_env())) {
129
				(*env)->CallVoidMethod(env, lock, ctx.releaseID);
130
				belle_sip_message("wake_lock_release(): Android wake lock released [ref=%p]", (void *)lock);
François Grisez's avatar
François Grisez committed
131
				(*env)->DeleteGlobalRef(env, lock);
132
			} else {
François Grisez's avatar
François Grisez committed
133
				belle_sip_error("bellesip_wake_lock_release(): cannot attach current thread to the JVM");
134 135 136
			}
		}
	} else {
137
		belle_sip_error("wake_lock_release(): cannot release wake lock. No JVM found");
138 139
	}
}