FreeRDP
android_jni_callback.c
1 
12 #include <freerdp/config.h>
13 
14 #include <stdio.h>
15 
16 #include "android_jni_callback.h"
17 #include "android_freerdp_jni.h"
18 
19 #include <freerdp/log.h>
20 #define TAG CLIENT_TAG("android.callback")
21 
22 static JavaVM* jVM;
23 static jobject jLibFreeRDPObject;
24 
25 static const char* jLibFreeRDPPath = JAVA_LIBFREERDP_CLASS;
26 
27 static void jni_load_class(JNIEnv* env, const char* path, jobject* objptr)
28 {
29  jclass class;
30  jmethodID method;
31  jobject object;
32  WLog_DBG(TAG, "jni_load_class: %s", path);
33  class = (*env)->FindClass(env, path);
34 
35  if (!class)
36  {
37  WLog_ERR(TAG, "jni_load_class: failed to find class %s", path);
38  goto finish;
39  }
40 
41  method = (*env)->GetMethodID(env, class, "<init>", "()V");
42 
43  if (!method)
44  {
45  WLog_ERR(TAG, "jni_load_class: failed to find class constructor of %s", path);
46  goto finish;
47  }
48 
49  object = (*env)->NewObject(env, class, method);
50 
51  if (!object)
52  {
53  WLog_ERR(TAG, "jni_load_class: failed create new object of %s", path);
54  goto finish;
55  }
56 
57  (*objptr) = (*env)->NewGlobalRef(env, object);
58 finish:
59 
60  while (0)
61  ;
62 }
63 
64 jint init_callback_environment(JavaVM* vm, JNIEnv* env)
65 {
66  jVM = vm;
67  jni_load_class(env, jLibFreeRDPPath, &jLibFreeRDPObject);
68  return JNI_VERSION_1_6;
69 }
70 
71 /* attach current thread to jvm */
72 jboolean jni_attach_thread(JNIEnv** env)
73 {
74  if ((*jVM)->GetEnv(jVM, (void**)env, JNI_VERSION_1_4) != JNI_OK)
75  {
76  WLog_DBG(TAG, "android_java_callback: attaching current thread");
77  (*jVM)->AttachCurrentThread(jVM, env, NULL);
78 
79  if ((*jVM)->GetEnv(jVM, (void**)env, JNI_VERSION_1_4) != JNI_OK)
80  {
81  WLog_ERR(TAG, "android_java_callback: failed to obtain current JNI environment");
82  }
83 
84  return JNI_TRUE;
85  }
86 
87  return JNI_FALSE;
88 }
89 
90 /* attach current thread to JVM */
91 void jni_detach_thread()
92 {
93  (*jVM)->DetachCurrentThread(jVM);
94 }
95 
96 /* callback with void result */
97 static void java_callback_void(jobject obj, const char* callback, const char* signature,
98  va_list args)
99 {
100  jclass jObjClass;
101  jmethodID jCallback;
102  jboolean attached;
103  JNIEnv* env;
104  WLog_DBG(TAG, "java_callback: %s (%s)", callback, signature);
105  attached = jni_attach_thread(&env);
106  jObjClass = (*env)->GetObjectClass(env, obj);
107 
108  if (!jObjClass)
109  {
110  WLog_ERR(TAG, "android_java_callback: failed to get class reference");
111  goto finish;
112  }
113 
114  jCallback = (*env)->GetStaticMethodID(env, jObjClass, callback, signature);
115 
116  if (!jCallback)
117  {
118  WLog_ERR(TAG, "android_java_callback: failed to get method id");
119  goto finish;
120  }
121 
122  (*env)->CallStaticVoidMethodV(env, jObjClass, jCallback, args);
123 finish:
124 
125  if (attached == JNI_TRUE)
126  jni_detach_thread();
127 }
128 
129 /* callback with bool result */
130 static jboolean java_callback_bool(jobject obj, const char* callback, const char* signature,
131  va_list args)
132 {
133  jclass jObjClass;
134  jmethodID jCallback;
135  jboolean attached;
136  jboolean res = JNI_FALSE;
137  JNIEnv* env;
138  WLog_DBG(TAG, "java_callback: %s (%s)", callback, signature);
139  attached = jni_attach_thread(&env);
140  jObjClass = (*env)->GetObjectClass(env, obj);
141 
142  if (!jObjClass)
143  {
144  WLog_ERR(TAG, "android_java_callback: failed to get class reference");
145  goto finish;
146  }
147 
148  jCallback = (*env)->GetStaticMethodID(env, jObjClass, callback, signature);
149 
150  if (!jCallback)
151  {
152  WLog_ERR(TAG, "android_java_callback: failed to get method id");
153  goto finish;
154  }
155 
156  res = (*env)->CallStaticBooleanMethodV(env, jObjClass, jCallback, args);
157 finish:
158 
159  if (attached == JNI_TRUE)
160  jni_detach_thread();
161 
162  return res;
163 }
164 
165 /* callback with int result */
166 static jint java_callback_int(jobject obj, const char* callback, const char* signature,
167  va_list args)
168 {
169  jclass jObjClass;
170  jmethodID jCallback;
171  jboolean attached;
172  jint res = -1;
173  JNIEnv* env;
174  WLog_DBG(TAG, "java_callback: %s (%s)", callback, signature);
175  attached = jni_attach_thread(&env);
176  jObjClass = (*env)->GetObjectClass(env, obj);
177 
178  if (!jObjClass)
179  {
180  WLog_ERR(TAG, "android_java_callback: failed to get class reference");
181  goto finish;
182  }
183 
184  jCallback = (*env)->GetStaticMethodID(env, jObjClass, callback, signature);
185 
186  if (!jCallback)
187  {
188  WLog_ERR(TAG, "android_java_callback: failed to get method id");
189  goto finish;
190  }
191 
192  res = (*env)->CallStaticIntMethodV(env, jObjClass, jCallback, args);
193 finish:
194 
195  if (attached == JNI_TRUE)
196  jni_detach_thread();
197 
198  return res;
199 }
200 
201 /* callback to freerdp class */
202 void freerdp_callback(const char* callback, const char* signature, ...)
203 {
204  va_list vl;
205  va_start(vl, signature);
206  java_callback_void(jLibFreeRDPObject, callback, signature, vl);
207  va_end(vl);
208 }
209 
210 jboolean freerdp_callback_bool_result(const char* callback, const char* signature, ...)
211 {
212  va_list vl;
213  va_start(vl, signature);
214  jboolean res = java_callback_bool(jLibFreeRDPObject, callback, signature, vl);
215  va_end(vl);
216  return res;
217 }
218 
219 jint freerdp_callback_int_result(const char* callback, const char* signature, ...)
220 {
221  va_list vl;
222  va_start(vl, signature);
223  jint res = java_callback_int(jLibFreeRDPObject, callback, signature, vl);
224  va_end(vl);
225  return res;
226 }