1 #include "wakelock_internal.h"
2 #include "belle-sip/utils.h"
3 #include <pthread.h>
4
5 struct _WakeLock {
6 JavaVM *jvm;
7 jobject powerManager;
8 pthread_key_t jniEnvKey;
9 jint PARTIAL_WAKE_LOCK;
10 jmethodID newWakeLockID;
11 jmethodID acquireID;
12 jmethodID releaseID;
13 };
14
15 typedef struct _WakeLock WakeLock;
16
17 static WakeLock ctx = {
18 .jvm = NULL,
19 .powerManager = NULL
20 };
21
22 static JNIEnv *get_jni_env(void);
23 static void jni_key_cleanup(void *data);
24
belle_sip_wake_lock_init(JNIEnv * env,jobject pm)25 void belle_sip_wake_lock_init(JNIEnv *env, jobject pm) {
26 if (ctx.jvm == NULL) {
27 jclass powerManagerClass;
28 jclass wakeLockClass;
29 jfieldID fieldID;
30
31 (*env)->GetJavaVM(env, &ctx.jvm);
32 pthread_key_create(&ctx.jniEnvKey, jni_key_cleanup);
33
34 powerManagerClass = (*env)->FindClass(env, "android/os/PowerManager");
35 wakeLockClass = (*env)->FindClass(env, "android/os/PowerManager$WakeLock");
36 fieldID = (*env)->GetStaticFieldID(env, powerManagerClass, "PARTIAL_WAKE_LOCK", "I");
37
38 ctx.PARTIAL_WAKE_LOCK = (*env)->GetStaticIntField(env, powerManagerClass, fieldID);
39 ctx.newWakeLockID = (*env)->GetMethodID(env, powerManagerClass, "newWakeLock", "(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;");
40 ctx.acquireID = (*env)->GetMethodID(env, wakeLockClass, "acquire", "()V");
41 ctx.releaseID = (*env)->GetMethodID(env, wakeLockClass, "release", "()V");
42
43 belle_sip_message("bellesip_wake_lock_init(): initialization succeed");
44 } else {
45 belle_sip_warning("bellesip_wake_lock_init(): the wakelock system has already been initialized");
46 }
47 if (ctx.powerManager == NULL) {
48 ctx.powerManager = (*env)->NewGlobalRef(env, pm);
49 }
50 }
51
belle_sip_wake_lock_uninit(JNIEnv * env)52 void belle_sip_wake_lock_uninit(JNIEnv *env) {
53 ctx.jvm = NULL;
54 if(ctx.powerManager != NULL) {
55 (*env)->DeleteGlobalRef(env, ctx.powerManager);
56 ctx.powerManager = NULL;
57 }
58 }
59
60 /**
61 * @brief Callback called when a thread terminates it-self.
62 * It detaches the thread from the JVM.
63 * @param data Unused.
64 */
jni_key_cleanup(void * data)65 static void jni_key_cleanup(void *data) {
66 JNIEnv *env = (JNIEnv*) data;
67 belle_sip_message("Thread end. Cleanup wake lock jni environment");
68 if (env != NULL) {
69 if (ctx.jvm != NULL) {
70 (*ctx.jvm)->DetachCurrentThread(ctx.jvm);
71 pthread_setspecific(ctx.jniEnvKey, NULL);
72 } else {
73 belle_sip_error("Wake lock cleanup. No JVM found");
74 }
75 }
76 }
77
78 /**
79 * @brief Get a JNI environment.
80 * Get a JNI by attaching the current thread
81 * to the internaly stored JVM. That function can be safely
82 * called several times.
83 * @return JNI environement pointer. NULL if the function fails.
84 */
get_jni_env(void)85 static JNIEnv *get_jni_env(void) {
86 JNIEnv *jenv = NULL;
87 if(ctx.jvm != NULL) {
88 jenv = pthread_getspecific(ctx.jniEnvKey);
89 if(jenv == NULL) {
90 if((*ctx.jvm)->AttachCurrentThread(ctx.jvm, &jenv, NULL) == JNI_OK) {
91 pthread_setspecific(ctx.jniEnvKey, jenv);
92 belle_sip_message("get_jni_env(): thread successfuly attached");
93 } else {
94 belle_sip_fatal("get_jni_env(): thread could not be attached to the JVM");
95 jenv = NULL;
96 }
97 }
98 } else {
99 belle_sip_error("get_jni_env(): no JVM found");
100 }
101 return jenv;
102 }
103
wake_lock_acquire(const char * tag)104 unsigned long wake_lock_acquire(const char *tag) {
105 if(ctx.jvm != NULL && ctx.powerManager != NULL) {
106 JNIEnv *env;
107 if((env = get_jni_env())) {
108 jstring tagString = (*env)->NewStringUTF(env, tag);
109 jobject lock = (*env)->CallObjectMethod(env, ctx.powerManager, ctx.newWakeLockID, ctx.PARTIAL_WAKE_LOCK, tagString);
110 (*env)->DeleteLocalRef(env, tagString);
111 if(lock != NULL) {
112 (*env)->CallVoidMethod(env, lock, ctx.acquireID);
113 lock = (*env)->NewGlobalRef(env, lock);
114 belle_sip_message("bellesip_wake_lock_acquire(): Android wake lock acquired [ref=%p]", (void *)lock);
115 return (unsigned long)lock;
116 } else {
117 belle_sip_message("bellesip_wake_lock_acquire(): wake lock creation failed");
118 }
119 } else {
120 belle_sip_error("bellesip_wake_lock_acquire(): cannot attach current thread to the JVM");
121 }
122 } else {
123 if (ctx.jvm == NULL)
124 belle_sip_error("bellesip_wake_lock_acquire(): cannot acquire wake lock. No JVM found");
125 else
126 belle_sip_error("bellesip_wake_lock_acquire(): cannot acquire wake lock. No PowerManager found");
127 }
128 return 0;
129 }
130
131
wake_lock_release(unsigned long id)132 void wake_lock_release(unsigned long id) {
133 if(ctx.jvm != NULL && ctx.powerManager != NULL) {
134 if(id != 0) {
135 jobject lock = (jobject)id;
136 JNIEnv *env;
137 if((env = get_jni_env())) {
138 (*env)->CallVoidMethod(env, lock, ctx.releaseID);
139 belle_sip_message("bellesip_wake_lock_release(): Android wake lock released [ref=%p]", (void *)lock);
140 (*env)->DeleteGlobalRef(env, lock);
141 } else {
142 belle_sip_error("bellesip_wake_lock_release(): cannot attach current thread to the JVM");
143 }
144 }
145 } else {
146 if(ctx.jvm == NULL)
147 belle_sip_error("bellesip_wake_lock_release(): cannot release wake lock. No JVM found");
148 else
149 belle_sip_error("bellesip_wake_lock_release(): cannot release wake lock. No PowerManager found");
150 }
151 }
152