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