android: Remove references to libpts
[strongswan.git] / src / frontends / android / jni / libandroidbridge / byod / imc_android.c
1 /*
2 * Copyright (C) 2012-2013 Tobias Brunner
3 * Copyright (C) 2012 Christoph Buehler
4 * Copyright (C) 2012 Patrick Loetscher
5 * Copyright (C) 2011-2012 Andreas Steffen
6 * Hochschule fuer Technik Rapperswil
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #include "imc_android_state.h"
20 #include "../android_jni.h"
21 #include "../charonservice.h"
22
23 #include <tnc/tnc.h>
24 #include <imcv.h>
25 #include <imc/imc_agent.h>
26 #include <imc/imc_msg.h>
27 #include <pa_tnc/pa_tnc_msg.h>
28 #include <ietf/ietf_attr.h>
29 #include <ietf/ietf_attr_attr_request.h>
30 #include <ietf/ietf_attr_installed_packages.h>
31 #include <ietf/ietf_attr_pa_tnc_error.h>
32 #include <ietf/ietf_attr_product_info.h>
33 #include <ietf/ietf_attr_remediation_instr.h>
34 #include <ietf/ietf_attr_string_version.h>
35 #include <ita/ita_attr.h>
36 #include <ita/ita_attr_get_settings.h>
37 #include <tcg/pts/tcg_pts_attr_file_meas.h>
38 #include <tcg/pts/tcg_pts_attr_meas_algo.h>
39 #include <tcg/pts/tcg_pts_attr_proto_caps.h>
40 #include <tcg/pts/tcg_pts_attr_req_file_meas.h>
41 #include <os_info/os_info.h>
42
43 #include <tncif_pa_subtypes.h>
44
45 #include <pen/pen.h>
46 #include <utils/debug.h>
47
48 #include <stdio.h>
49
50 /* IMC definitions */
51
52 static const char imc_name[] = "Android";
53
54 static pen_type_t msg_types[] = {
55 { PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM },
56 { PEN_IETF, PA_SUBTYPE_IETF_VPN },
57 { PEN_TCG, PA_SUBTYPE_TCG_PTS },
58 };
59
60 static imc_agent_t *imc_android;
61
62 /**
63 * AndroidImc object accessed via JNI
64 */
65 static jobject android_imc;
66
67 /**
68 * AndroidImc class object
69 */
70 static jclass android_imc_cls;
71
72 /**
73 * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
74 */
75 static TNC_Result tnc_imc_initialize(TNC_IMCID imc_id,
76 TNC_Version min_version,
77 TNC_Version max_version,
78 TNC_Version *actual_version)
79 {
80 if (imc_android)
81 {
82 DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
83 return TNC_RESULT_ALREADY_INITIALIZED;
84 }
85 imc_android = imc_agent_create(imc_name, msg_types, countof(msg_types),
86 imc_id, actual_version);
87 if (!imc_android)
88 {
89 return TNC_RESULT_FATAL;
90 }
91
92 if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
93 {
94 DBG1(DBG_IMC, "no common IF-IMC version");
95 return TNC_RESULT_NO_COMMON_VERSION;
96 }
97 return TNC_RESULT_SUCCESS;
98 }
99
100 /**
101 * Update the state in the GUI.
102 */
103 static void update_imc_state(TNC_ConnectionState state)
104 {
105 android_imc_state_t imc_state = ANDROID_IMC_STATE_UNKNOWN;
106
107 switch (state)
108 { /* map connection states to the values used by the GUI */
109 case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
110 imc_state = ANDROID_IMC_STATE_ALLOW;
111 break;
112 case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
113 imc_state = ANDROID_IMC_STATE_ISOLATE;
114 break;
115 case TNC_CONNECTION_STATE_ACCESS_NONE:
116 imc_state = ANDROID_IMC_STATE_BLOCK;
117 break;
118 }
119
120 charonservice->update_imc_state(charonservice, imc_state);
121 }
122
123 /**
124 * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
125 */
126 static TNC_Result tnc_imc_notifyconnectionchange(TNC_IMCID imc_id,
127 TNC_ConnectionID connection_id,
128 TNC_ConnectionState new_state)
129 {
130 imc_state_t *state;
131
132 if (!imc_android)
133 {
134 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
135 return TNC_RESULT_NOT_INITIALIZED;
136 }
137 switch (new_state)
138 {
139 case TNC_CONNECTION_STATE_CREATE:
140 state = imc_android_state_create(connection_id);
141 return imc_android->create_state(imc_android, state);
142 case TNC_CONNECTION_STATE_HANDSHAKE:
143 if (imc_android->change_state(imc_android, connection_id, new_state,
144 &state) != TNC_RESULT_SUCCESS)
145 {
146 return TNC_RESULT_FATAL;
147 }
148 state->set_result(state, imc_id,
149 TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
150 return TNC_RESULT_SUCCESS;
151 case TNC_CONNECTION_STATE_DELETE:
152 return imc_android->delete_state(imc_android, connection_id);
153 case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
154 case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
155 case TNC_CONNECTION_STATE_ACCESS_NONE:
156 update_imc_state(new_state);
157 /* fall-through */
158 default:
159 return imc_android->change_state(imc_android, connection_id,
160 new_state, NULL);
161 }
162 }
163
164 /**
165 * Convert the native C strings in the enumerator to a Java String array.
166 * The given enumerator gets destroyed.
167 */
168 static jobjectArray string_array_create(JNIEnv *env, enumerator_t *enumerator)
169 {
170 linked_list_t *list;
171 jobjectArray jarray;
172 jstring jstring;
173 char *native;
174 jclass cls;
175 int i = 0;
176
177 cls = (*env)->FindClass(env, "java/lang/String");
178 list = linked_list_create_from_enumerator(enumerator);
179 jarray = (*env)->NewObjectArray(env, list->get_count(list), cls, NULL);
180 if (!jarray)
181 {
182 goto failed;
183 }
184 enumerator = list->create_enumerator(list);
185 while (enumerator->enumerate(enumerator, (void**)&native))
186 {
187 jstring = (*env)->NewStringUTF(env, native);
188 if (!jstring)
189 {
190 enumerator->destroy(enumerator);
191 goto failed;
192 }
193 (*env)->SetObjectArrayElement(env, jarray, i++, jstring);
194 }
195 enumerator->destroy(enumerator);
196 list->destroy(list);
197 return jarray;
198
199 failed:
200 androidjni_exception_occurred(env);
201 list->destroy(list);
202 return NULL;
203 }
204
205 /**
206 * Get a measurement for the given attribute type from the Android IMC.
207 * NULL is returned if no measurement is available or an error occurred.
208 *
209 * The optional args is an enumerator over char* (gets destroyed).
210 */
211 static pa_tnc_attr_t *get_measurement(pen_type_t attr_type, enumerator_t *args)
212 {
213 JNIEnv *env;
214 pa_tnc_attr_t *attr;
215 jmethodID method_id;
216 jbyteArray jmeasurement;
217 jobjectArray jargs = NULL;
218 chunk_t data;
219
220 androidjni_attach_thread(&env);
221 if (args)
222 {
223 jargs = string_array_create(env, args);
224 if (!jargs)
225 {
226 goto failed;
227 }
228 method_id = (*env)->GetMethodID(env, android_imc_cls, "getMeasurement",
229 "(II[Ljava/lang/String;)[B");
230 }
231 else
232 {
233 method_id = (*env)->GetMethodID(env, android_imc_cls, "getMeasurement",
234 "(II)[B");
235 }
236 if (!method_id)
237 {
238 goto failed;
239 }
240 jmeasurement = (*env)->CallObjectMethod(env, android_imc, method_id,
241 attr_type.vendor_id, attr_type.type,
242 jargs);
243 if (!jmeasurement || androidjni_exception_occurred(env))
244 {
245 goto failed;
246 }
247 data = chunk_create((*env)->GetByteArrayElements(env, jmeasurement, NULL),
248 (*env)->GetArrayLength(env, jmeasurement));
249 if (!data.ptr)
250 {
251 goto failed;
252 }
253 attr = imcv_pa_tnc_attributes->create(imcv_pa_tnc_attributes,
254 attr_type.vendor_id, attr_type.type,
255 data);
256 (*env)->ReleaseByteArrayElements(env, jmeasurement, data.ptr, JNI_ABORT);
257 androidjni_detach_thread();
258 return attr;
259
260 failed:
261 androidjni_exception_occurred(env);
262 androidjni_detach_thread();
263 return NULL;
264 }
265
266 /**
267 * Add the measurement for the requested attribute type with optional
268 * arguments (enumerator over char*, gets destroyed).
269 */
270 static void add_measurement(pen_type_t attr_type, imc_msg_t *msg,
271 enumerator_t *args)
272 {
273 pa_tnc_attr_t *attr;
274 enum_name_t *pa_attr_names;
275
276 attr = get_measurement(attr_type, args);
277 if (attr)
278 {
279 msg->add_attribute(msg, attr);
280 return;
281 }
282 pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
283 attr_type.vendor_id);
284 if (pa_attr_names)
285 {
286 DBG1(DBG_IMC, "no measurement available for PA-TNC attribute type "
287 "'%N/%N' 0x%06x/0x%08x", pen_names, attr_type.vendor_id,
288 pa_attr_names, attr_type.type, attr_type.vendor_id, attr_type.type);
289 }
290 else
291 {
292 DBG1(DBG_IMC, "no measurement available for PA-TNC attribute type '%N' "
293 "0x%06x/0x%08x", pen_names, attr_type.vendor_id,
294 attr_type.vendor_id, attr_type.type);
295 }
296 }
297
298 /**
299 * Handle an IETF attribute
300 */
301 static void handle_ietf_attribute(pen_type_t attr_type, pa_tnc_attr_t *attr,
302 imc_msg_t *out_msg)
303 {
304 if (attr_type.type == IETF_ATTR_ATTRIBUTE_REQUEST)
305 {
306 ietf_attr_attr_request_t *attr_cast;
307 pen_type_t *entry;
308 enumerator_t *enumerator;
309
310 attr_cast = (ietf_attr_attr_request_t*)attr;
311 enumerator = attr_cast->create_enumerator(attr_cast);
312 while (enumerator->enumerate(enumerator, &entry))
313 {
314 add_measurement(*entry, out_msg, NULL);
315 }
316 enumerator->destroy(enumerator);
317 }
318 else if (attr_type.type == IETF_ATTR_REMEDIATION_INSTRUCTIONS)
319 {
320 ietf_attr_remediation_instr_t *attr_cast;
321 pen_type_t param;
322 chunk_t str;
323 char *instr;
324
325 attr_cast = (ietf_attr_remediation_instr_t*)attr;
326 param = attr_cast->get_parameters_type(attr_cast);
327
328 if (pen_type_is(param, PEN_IETF, IETF_REMEDIATION_PARAMETERS_STRING))
329 {
330 str = attr_cast->get_string(attr_cast, NULL);
331 instr = strndup(str.ptr, str.len);
332 charonservice->add_remediation_instr(charonservice, instr);
333 free (instr);
334 }
335 }
336 }
337
338 /**
339 * Handle an ITA attribute
340 */
341 static void handle_ita_attribute(pen_type_t attr_type, pa_tnc_attr_t *attr,
342 imc_msg_t *out_msg)
343 {
344 if (attr_type.type == ITA_ATTR_GET_SETTINGS)
345 {
346 ita_attr_get_settings_t *attr_cast;
347
348 attr_cast = (ita_attr_get_settings_t*)attr;
349 add_measurement((pen_type_t){ PEN_ITA, ITA_ATTR_SETTINGS },
350 out_msg, attr_cast->create_enumerator(attr_cast));
351 }
352 }
353
354 /**
355 * Handle a TCG attribute
356 */
357 static void handle_tcg_attribute(imc_android_state_t *state,
358 pen_type_t attr_type, pa_tnc_attr_t *attr,
359 imc_msg_t *out_msg)
360 {
361 pts_t *pts;
362
363 pts = state->get_pts(state);
364 switch (attr_type.type)
365 {
366 case TCG_PTS_REQ_PROTO_CAPS:
367 {
368 tcg_pts_attr_proto_caps_t *attr_cast;
369 pts_proto_caps_flag_t caps;
370
371 attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
372 caps = attr_cast->get_flags(attr_cast) & pts->get_proto_caps(pts);
373 pts->set_proto_caps(pts, caps);
374 attr = tcg_pts_attr_proto_caps_create(caps, FALSE);
375 out_msg->add_attribute(out_msg, attr);
376 break;
377 }
378 case TCG_PTS_MEAS_ALGO:
379 {
380 tcg_pts_attr_meas_algo_t *attr_cast;
381 pts_meas_algorithms_t supported, algo;
382
383 if (!pts_meas_algo_probe(&supported))
384 {
385 attr = pts_hash_alg_error_create(PTS_MEAS_ALGO_NONE);
386 out_msg->add_attribute(out_msg, attr);
387 break;
388 }
389 attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
390 algo = pts_meas_algo_select(supported,
391 attr_cast->get_algorithms(attr_cast));
392 if (algo == PTS_MEAS_ALGO_NONE)
393 {
394 attr = pts_hash_alg_error_create(supported);
395 out_msg->add_attribute(out_msg, attr);
396 break;
397 }
398 pts->set_meas_algorithm(pts, algo);
399 attr = tcg_pts_attr_meas_algo_create(algo, TRUE);
400 out_msg->add_attribute(out_msg, attr);
401 break;
402 }
403 case TCG_PTS_REQ_FILE_MEAS:
404 {
405 tcg_pts_attr_req_file_meas_t *attr_cast;
406 pts_file_meas_t *measurements;
407 pts_error_code_t pts_error;
408 u_int32_t delim;
409 u_int16_t req_id;
410 bool is_dir;
411 char *path;
412
413 attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
414 path = attr_cast->get_pathname(attr_cast);
415 if (!pts->is_path_valid(pts, path, &pts_error))
416 { /* silently ignore internal errors */
417 break;
418 }
419 else if (pts_error)
420 {
421 attr = ietf_attr_pa_tnc_error_create(pen_type_create(PEN_TCG,
422 pts_error), attr->get_value(attr));
423 out_msg->add_attribute(out_msg, attr);
424 break;
425 }
426 delim = attr_cast->get_delimiter(attr_cast);
427 if (delim != SOLIDUS_UTF && delim != REVERSE_SOLIDUS_UTF)
428 {
429 attr = ietf_attr_pa_tnc_error_create(pen_type_create(PEN_TCG,
430 TCG_PTS_INVALID_DELIMITER), attr->get_value(attr));
431 out_msg->add_attribute(out_msg, attr);
432 break;
433 }
434 req_id = attr_cast->get_request_id(attr_cast);
435 is_dir = attr_cast->get_directory_flag(attr_cast);
436
437 DBG1(DBG_IMC, "measurement request %d for %s '%s'", req_id,
438 is_dir ? "directory" : "file", path);
439 measurements = pts_file_meas_create_from_path(req_id, path, is_dir,
440 TRUE, pts->get_meas_algorithm(pts));
441 if (!measurements)
442 {
443 attr = ietf_attr_pa_tnc_error_create(pen_type_create(PEN_TCG,
444 TCG_PTS_FILE_NOT_FOUND), attr->get_value(attr));
445 out_msg->add_attribute(out_msg, attr);
446 break;
447 }
448 attr = tcg_pts_attr_file_meas_create(measurements);
449 attr->set_noskip_flag(attr, TRUE);
450 out_msg->add_attribute(out_msg, attr);
451 break;
452 }
453 default:
454 DBG1(DBG_IMC, "received unsupported TCG attribute '%N'",
455 tcg_attr_names, attr_type.type);
456 break;
457 }
458 }
459
460 /**
461 * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
462 */
463 static TNC_Result tnc_imc_beginhandshake(TNC_IMCID imc_id,
464 TNC_ConnectionID connection_id)
465 {
466 imc_state_t *state;
467 imc_msg_t *out_msg;
468 TNC_Result result = TNC_RESULT_SUCCESS;
469
470 if (!imc_android)
471 {
472 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
473 return TNC_RESULT_NOT_INITIALIZED;
474 }
475 if (!imc_android->get_state(imc_android, connection_id, &state))
476 {
477 return TNC_RESULT_FATAL;
478 }
479 if (lib->settings->get_bool(lib->settings,
480 "android.imc.send_os_info", TRUE))
481 {
482 out_msg = imc_msg_create(imc_android, state, connection_id, imc_id,
483 TNC_IMVID_ANY, msg_types[0]);
484 add_measurement((pen_type_t){ PEN_IETF, IETF_ATTR_PRODUCT_INFORMATION },
485 out_msg, NULL);
486 add_measurement((pen_type_t){ PEN_IETF, IETF_ATTR_STRING_VERSION },
487 out_msg, NULL);
488 add_measurement((pen_type_t){ PEN_ITA, ITA_ATTR_DEVICE_ID },
489 out_msg, NULL);
490 /* send PA-TNC message with the excl flag not set */
491 result = out_msg->send(out_msg, FALSE);
492 out_msg->destroy(out_msg);
493 }
494
495 return result;
496 }
497
498 static TNC_Result receive_message(imc_android_state_t *state, imc_msg_t *in_msg)
499 {
500 imc_msg_t *out_msg;
501 enumerator_t *enumerator;
502 pa_tnc_attr_t *attr;
503 pen_type_t attr_type;
504 TNC_Result result;
505 bool fatal_error = FALSE;
506
507 /* parse received PA-TNC message and handle local and remote errors */
508 result = in_msg->receive(in_msg, &fatal_error);
509 if (result != TNC_RESULT_SUCCESS)
510 {
511 return result;
512 }
513 out_msg = imc_msg_create_as_reply(in_msg);
514
515 /* analyze PA-TNC attributes */
516 enumerator = in_msg->create_attribute_enumerator(in_msg);
517 while (enumerator->enumerate(enumerator, &attr))
518 {
519 attr_type = attr->get_type(attr);
520
521 switch (attr_type.vendor_id)
522 {
523 case PEN_IETF:
524 handle_ietf_attribute(attr_type, attr, out_msg);
525 continue;
526 case PEN_ITA:
527 handle_ita_attribute(attr_type, attr, out_msg);
528 continue;
529 case PEN_TCG:
530 handle_tcg_attribute(state, attr_type, attr, out_msg);
531 continue;
532 default:
533 continue;
534 }
535 }
536 enumerator->destroy(enumerator);
537
538 if (fatal_error)
539 {
540 result = TNC_RESULT_FATAL;
541 }
542 else
543 {
544 result = out_msg->send(out_msg, TRUE);
545 }
546 out_msg->destroy(out_msg);
547
548 return result;
549 }
550
551 /**
552 * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
553
554 */
555 static TNC_Result tnc_imc_receivemessage(TNC_IMCID imc_id,
556 TNC_ConnectionID connection_id,
557 TNC_BufferReference msg,
558 TNC_UInt32 msg_len,
559 TNC_MessageType msg_type)
560 {
561 imc_state_t *state;
562 imc_msg_t *in_msg;
563 TNC_Result result;
564
565 if (!imc_android)
566 {
567 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
568 return TNC_RESULT_NOT_INITIALIZED;
569 }
570 if (!imc_android->get_state(imc_android, connection_id, &state))
571 {
572 return TNC_RESULT_FATAL;
573 }
574 in_msg = imc_msg_create_from_data(imc_android, state, connection_id,
575 msg_type, chunk_create(msg, msg_len));
576 result = receive_message((imc_android_state_t*)state, in_msg);
577 in_msg->destroy(in_msg);
578
579 return result;
580 }
581
582 /**
583 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
584 */
585 static TNC_Result tnc_imc_receivemessagelong(TNC_IMCID imc_id,
586 TNC_ConnectionID connection_id,
587 TNC_UInt32 msg_flags,
588 TNC_BufferReference msg,
589 TNC_UInt32 msg_len,
590 TNC_VendorID msg_vid,
591 TNC_MessageSubtype msg_subtype,
592 TNC_UInt32 src_imv_id,
593 TNC_UInt32 dst_imc_id)
594 {
595 imc_state_t *state;
596 imc_msg_t *in_msg;
597 TNC_Result result;
598
599 if (!imc_android)
600 {
601 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
602 return TNC_RESULT_NOT_INITIALIZED;
603 }
604 if (!imc_android->get_state(imc_android, connection_id, &state))
605 {
606 return TNC_RESULT_FATAL;
607 }
608 in_msg = imc_msg_create_from_long_data(imc_android, state, connection_id,
609 src_imv_id, dst_imc_id,msg_vid, msg_subtype,
610 chunk_create(msg, msg_len));
611 result = receive_message((imc_android_state_t*)state, in_msg);
612 in_msg->destroy(in_msg);
613
614 return result;
615 }
616
617 /**
618 * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
619 */
620 static TNC_Result tnc_imc_batchending(TNC_IMCID imc_id,
621 TNC_ConnectionID connection_id)
622 {
623 if (!imc_android)
624 {
625 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
626 return TNC_RESULT_NOT_INITIALIZED;
627 }
628 return TNC_RESULT_SUCCESS;
629 }
630
631 /**
632 * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
633 */
634 static TNC_Result tnc_imc_terminate(TNC_IMCID imc_id)
635 {
636 if (!imc_android)
637 {
638 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
639 return TNC_RESULT_NOT_INITIALIZED;
640 }
641 imc_android->destroy(imc_android);
642 imc_android = NULL;
643 return TNC_RESULT_SUCCESS;
644 }
645
646 /**
647 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
648 */
649 static TNC_Result tnc_imc_providebindfunction(TNC_IMCID imc_id,
650 TNC_TNCC_BindFunctionPointer bind_function)
651 {
652 if (!imc_android)
653 {
654 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
655 return TNC_RESULT_NOT_INITIALIZED;
656 }
657 return imc_android->bind_functions(imc_android, bind_function);
658 }
659
660 /*
661 * Described in header
662 */
663 bool imc_android_register(plugin_t *plugin, plugin_feature_t *feature,
664 bool reg, void *data)
665 {
666 JNIEnv *env;
667 jmethodID method_id;
668 jobject obj, context = (jobject)data;
669 jclass cls;
670 bool success = TRUE;
671
672 androidjni_attach_thread(&env);
673 if (reg)
674 {
675 cls = (*env)->FindClass(env, JNI_PACKAGE_STRING "/imc/AndroidImc");
676 if (!cls)
677 {
678 goto failed;
679 }
680 android_imc_cls = (*env)->NewGlobalRef(env, cls);
681 method_id = (*env)->GetMethodID(env, cls, "<init>",
682 "(Landroid/content/Context;)V");
683 if (!method_id)
684 {
685 goto failed;
686 }
687 obj = (*env)->NewObject(env, cls, method_id, context);
688 if (!obj)
689 {
690 goto failed;
691 }
692 android_imc = (*env)->NewGlobalRef(env, obj);
693 androidjni_detach_thread();
694
695 if (tnc->imcs->load_from_functions(tnc->imcs, "Android",
696 tnc_imc_initialize, tnc_imc_notifyconnectionchange,
697 tnc_imc_beginhandshake, tnc_imc_receivemessage,
698 tnc_imc_receivemessagelong, tnc_imc_batchending,
699 tnc_imc_terminate, tnc_imc_providebindfunction))
700 {
701 return TRUE;
702 }
703 failed:
704 DBG1(DBG_IMC, "initialization of Android IMC failed");
705 androidjni_exception_occurred(env);
706 success = FALSE;
707 }
708
709 if (android_imc)
710 {
711 (*env)->DeleteGlobalRef(env, android_imc);
712 android_imc = NULL;
713 }
714 if (android_imc_cls)
715 {
716 (*env)->DeleteGlobalRef(env, android_imc_cls);
717 android_imc_cls = NULL;
718 }
719 androidjni_detach_thread();
720 return success;
721 }