mirror of
				https://github.com/bytecodealliance/wasm-micro-runtime.git
				synced 2025-10-31 05:11:19 +00:00 
			
		
		
		
	 32242988ed
			
		
	
	
		32242988ed
		
			
		
	
	
	
	
		
			
			Apply clang-format for C source files in folder core/app-mgr, core/app-framework, and test-tools. And rename folder component_test to component-test, update zephyr build document. Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
		
			
				
	
	
		
			1884 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1884 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2019 Intel Corporation.  All rights reserved.
 | |
|  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
|  */
 | |
| 
 | |
| #ifdef ENABLE_JEFF
 | |
| 
 | |
| #include "module_jeff.h"
 | |
| #include "jeff_export.h"
 | |
| #include "../vmcore_jeff/jeff-runtime.h"
 | |
| #include "../vmcore_jeff/jeff-thread.h"
 | |
| #include "../vmcore_jeff/jeff-buffer.h"
 | |
| #include "../vmcore_jeff/jeff-tool.h"
 | |
| #include "../vmcore_jeff/jeff-tool-priv.h"
 | |
| #include "app_manager-host.h"
 | |
| #include "bh_queue.h"
 | |
| #include "attr-container.h"
 | |
| #include "attr-container-util.h"
 | |
| #include "bh_thread.h"
 | |
| #include "ems_gc.h"
 | |
| #include "coap_ext.h"
 | |
| #include "libcore.h"
 | |
| #include "event.h"
 | |
| #include "watchdog.h"
 | |
| 
 | |
| #define DEFAULT_APPLET_TIMEOUT (3 * 60 * 1000)
 | |
| #define DEFAULT_APPLET_HEAP_SIZE (48 * 1024)
 | |
| #define MIN_APPLET_HEAP_SIZE (2 * 1024)
 | |
| #define MAX_APPLET_HEAP_SIZE (1024 * 1024)
 | |
| 
 | |
| typedef struct jeff_applet_data {
 | |
|     /* Java Applet Object */
 | |
|     JeffObjectRef applet_obj;
 | |
| 
 | |
| #if BEIHAI_ENABLE_TOOL_AGENT != 0
 | |
|     /* Whether the applet is in debug mode */
 | |
|     bool debug_mode;
 | |
|     /* Queue of the tool agent */
 | |
|     bh_queue *tool_agent_queue;
 | |
| #endif
 | |
| 
 | |
|     /* VM instance */
 | |
|     JeffInstanceLocalRoot *vm_instance;
 | |
|     /* Applet Main file */
 | |
|     JeffFileHeaderLinked *main_file;
 | |
|     /* Permissions of the Java Applet */
 | |
|     char *perms;
 | |
| } jeff_applet_data;
 | |
| 
 | |
| /* Jeff class com.intel.aee.AEEApplet */
 | |
| static JeffClassHeaderLinked *class_AEEApplet;
 | |
| /* Jeff class com.intel.aee.Request */
 | |
| static JeffClassHeaderLinked *class_AEERequest;
 | |
| /* Jeff class com.intel.aee.Timer */
 | |
| static JeffClassHeaderLinked *class_Timer;
 | |
| /* Jeff class com.intel.aee.Sensor */
 | |
| static JeffClassHeaderLinked *class_Sensor;
 | |
| /* Jeff class com.intel.aee.ble.BLEManager */
 | |
| static JeffClassHeaderLinked *class_BLEManager;
 | |
| /* Jeff class com.intel.aee.ble.BLEDevice */
 | |
| static JeffClassHeaderLinked *class_BLEDevice;
 | |
| /* Jeff class com.intel.aee.ble.BLEGattService */
 | |
| JeffClassHeaderLinked *class_BLEGattService;
 | |
| /* Jeff class com.intel.aee.ble.BLEGattCharacteristic */
 | |
| JeffClassHeaderLinked *class_BLEGattCharacteristic;
 | |
| /* Jeff class com.intel.aee.ble.BLEGattDescriptor */
 | |
| JeffClassHeaderLinked *class_BLEGattDescriptor;
 | |
| /* Jeff class com.intel.aee.gpio.GPIOChannel */
 | |
| static JeffClassHeaderLinked *class_GPIOChannel;
 | |
| /* Jeff method void com.intel.aee.AEEApplet.onInit() */
 | |
| static JeffMethodLinked *method_AEEApplet_onInit;
 | |
| /* Jeff method void com.intel.aee.AEEApplet.onDestroy() */
 | |
| static JeffMethodLinked *method_AEEApplet_onDestroy;
 | |
| /* Jeff method void com.intel.aee.AEEApplet.callOnRequest(Request request) */
 | |
| static JeffMethodLinked *method_AEEApplet_callOnRequest;
 | |
| /* Jeff method void com.intel.aee.Timer.callOnTimer() */
 | |
| static JeffMethodLinked *method_callOnTimer;
 | |
| /* Jeff method void com.intel.aee.Sensor.callOnSensorEvent() */
 | |
| static JeffMethodLinked *method_callOnSensorEvent;
 | |
| /* Jeff method void com.intel.aee.ble.BLEManager.callOnBLEStartDiscovery() */
 | |
| static JeffMethodLinked *method_callOnBLEStartDiscovery;
 | |
| /* Jeff method void com.intel.aee.ble.BLEManager.callOnBLEConnected() */
 | |
| static JeffMethodLinked *method_callOnBLEConnected;
 | |
| /* Jeff method void com.intel.aee.ble.BLEManager.callOnBLEDisonnected() */
 | |
| static JeffMethodLinked *method_callOnBLEDisconnected;
 | |
| /* Jeff method void com.intel.aee.ble.BLEManager.callOnBLENotification() */
 | |
| static JeffMethodLinked *method_callOnBLENotification;
 | |
| /* Jeff method void com.intel.aee.ble.BLEManager.callOnBLEIndication() */
 | |
| static JeffMethodLinked *method_callOnBLEIndication;
 | |
| /* Jeff method void com.intel.aee.ble.BLEManager.callOnBLEPasskeyEntry() */
 | |
| static JeffMethodLinked *method_callOnBLEPasskeyEntry;
 | |
| /* Jeff method void com.intel.aee.gpio.GPIOChannel.callOnGPIOInterrupt() */
 | |
| static JeffMethodLinked *method_callOnGPIOInterrupt;
 | |
| /* Jeff method void com.intel.aee.ble.BLEManager.getBLEDevice() */
 | |
| static JeffMethodLinked *method_callOnBLEManagerGetBLEDevice;
 | |
| 
 | |
| static jeff_applet_data *
 | |
| app_manager_get_jeff_applet_data()
 | |
| {
 | |
|     module_data *m_data = app_manager_get_module_data(Module_Jeff);
 | |
|     return (jeff_applet_data *)m_data->internal_data;
 | |
| }
 | |
| 
 | |
| #if BEIHAI_ENABLE_TOOL_AGENT != 0
 | |
| void *
 | |
| app_manager_get_tool_agent_queue()
 | |
| {
 | |
|     return app_manager_get_jeff_applet_data()->tool_agent_queue;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if BEIHAI_ENABLE_TOOL_AGENT != 0
 | |
| static bool
 | |
| is_tool_agent_running(module_data *m_data)
 | |
| {
 | |
|     jeff_applet_data *applet_data = (jeff_applet_data *)m_data->internal_data;
 | |
|     return (applet_data->debug_mode && applet_data->tool_agent_queue
 | |
|             && applet_data->vm_instance->tool_agent);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static char *
 | |
| get_class_qname(const JeffString *pname, const JeffString *cname)
 | |
| {
 | |
|     unsigned int length =
 | |
|         pname->length ? pname->length + 2 + cname->length : cname->length + 1;
 | |
|     char *buf = APP_MGR_MALLOC(length), *p;
 | |
| 
 | |
|     if (!buf)
 | |
|         return NULL;
 | |
| 
 | |
|     p = buf;
 | |
|     if (pname->length) {
 | |
|         bh_memcpy_s(p, pname->length, pname->value, pname->length);
 | |
|         p += pname->length;
 | |
|         *p++ = '.';
 | |
|     }
 | |
| 
 | |
|     bh_memcpy_s(p, cname->length, cname->value, cname->length);
 | |
|     p += cname->length;
 | |
|     *p = '\0';
 | |
| 
 | |
|     return buf;
 | |
| }
 | |
| 
 | |
| static void
 | |
| send_exception_event_to_host(const char *applet_name, const char *exc_name)
 | |
| {
 | |
|     attr_container_t *payload;
 | |
|     bh_request_msg_t msg;
 | |
|     char *url;
 | |
|     int url_len;
 | |
| 
 | |
|     payload = attr_container_create("exception detail");
 | |
|     if (!payload) {
 | |
|         app_manager_printf("Send exception to host fail: allocate memory");
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (!attr_container_set_string(&payload, "exception name", exc_name)
 | |
|         || !attr_container_set_string(&payload, "stack trace", "TODO")
 | |
|         || !attr_container_set_string(&payload, "applet name", applet_name)) {
 | |
|         app_manager_printf("Send exception to host fail: set attr");
 | |
|         goto fail;
 | |
|     }
 | |
| 
 | |
|     url_len = strlen("/exception/") + strlen(applet_name);
 | |
|     url = APP_MGR_MALLOC(url_len + 1);
 | |
|     if (!url) {
 | |
|         app_manager_printf("Send exception to host fail: allocate memory");
 | |
|         goto fail;
 | |
|     }
 | |
|     memset(url, 0, url_len + 1);
 | |
|     bh_strcpy_s(url, url_len + 1, "/exception/");
 | |
|     bh_strcat_s(url, url_len + 1, applet_name);
 | |
| 
 | |
|     memset(&msg, 0, sizeof(msg));
 | |
|     msg.url = url;
 | |
|     msg.action = COAP_PUT;
 | |
|     msg.payload = (char *)payload;
 | |
| 
 | |
|     app_send_request_msg_to_host(&msg);
 | |
| 
 | |
|     APP_MGR_FREE(url);
 | |
| 
 | |
| fail:
 | |
|     attr_container_destroy(payload);
 | |
| }
 | |
| 
 | |
| static bool
 | |
| check_exception()
 | |
| {
 | |
|     if (jeff_runtime_get_exception()) {
 | |
|         jeff_printf("V1.Exception thrown when running applet '%s':\n",
 | |
|                     app_manager_get_module_name(Module_Jeff));
 | |
|         jeff_runtime_print_exception();
 | |
|         jeff_printf("\n");
 | |
|         jeff_printf(NULL);
 | |
|     }
 | |
| 
 | |
|     if (!app_manager_is_interrupting_module(Module_Jeff)) {
 | |
|         attr_container_t *payload;
 | |
|         int payload_len;
 | |
|         JeffClassHeaderLinked *exc_class =
 | |
|             jeff_object_class_pointer(jeff_runtime_get_exception());
 | |
|         char *qname_buf = get_class_qname(jeff_get_class_pname(exc_class),
 | |
|                                           jeff_get_class_cname(exc_class));
 | |
| 
 | |
|         /* Send exception event to host */
 | |
|         if (qname_buf) {
 | |
|             send_exception_event_to_host(
 | |
|                 app_manager_get_module_name(Module_Jeff), qname_buf);
 | |
|             APP_MGR_FREE(qname_buf);
 | |
|         }
 | |
| 
 | |
|         /* Uninstall the applet */
 | |
|         if ((payload = attr_container_create("uninstall myself"))) {
 | |
|             if (attr_container_set_string(
 | |
|                     &payload, "name", app_manager_get_module_name(Module_Jeff))
 | |
|                 /* Set special flag to prevent app manager making response
 | |
|                    since this is an internal message */
 | |
|                 && attr_container_set_bool(&payload, "do not reply me", true)) {
 | |
|                 request_t request = { 0 };
 | |
|                 payload_len = attr_container_get_serialize_length(payload);
 | |
| 
 | |
|                     init_request(request, "/applet", COAP_DELETE, (char *)payload, payload_len));
 | |
|                     app_mgr_lookup_resource(&request);
 | |
| 
 | |
|                     // TODO: confirm this is right
 | |
|                     attr_container_destroy(payload);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         jeff_runtime_set_exception(NULL);
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| static bool
 | |
| app_manager_initialize_class(JeffClassHeaderLinked *c)
 | |
| {
 | |
|     jeff_runtime_initialize_class(c);
 | |
|     return !check_exception();
 | |
| }
 | |
| 
 | |
| static bool
 | |
| app_manager_initialize_object(JeffObjectRef obj)
 | |
| {
 | |
|     jeff_runtime_initialize_object(obj);
 | |
|     return !check_exception();
 | |
| }
 | |
| 
 | |
| static bool
 | |
| app_manager_call_java(JeffMethodLinked *method, unsigned int argc,
 | |
|                       uint32 argv[], uint8 argt[])
 | |
| {
 | |
|     module_data *m_data = app_manager_get_module_data(Module_Jeff);
 | |
|     watchdog_timer *wd_timer = &m_data->wd_timer;
 | |
|     bool is_wd_started = false;
 | |
| 
 | |
| #if BEIHAI_ENABLE_TOOL_AGENT != 0
 | |
|     /* Only start watchdog when debugger is not running */
 | |
|     if (!is_tool_agent_running(m_data)) {
 | |
| #endif
 | |
|         watchdog_timer_start(wd_timer);
 | |
|         is_wd_started = true;
 | |
| #if BEIHAI_ENABLE_TOOL_AGENT != 0
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     jeff_runtime_call_java(method, argc, argv, argt);
 | |
| 
 | |
|     if (is_wd_started) {
 | |
|         os_mutex_lock(&wd_timer->lock);
 | |
|         if (!wd_timer->is_interrupting) {
 | |
|             wd_timer->is_stopped = true;
 | |
|             watchdog_timer_stop(wd_timer);
 | |
|         }
 | |
|         os_mutex_unlock(&wd_timer->lock);
 | |
|     }
 | |
| 
 | |
|     return !check_exception();
 | |
| }
 | |
| 
 | |
| static AEEBLEDevice
 | |
| create_object_BLEDevice(ble_device_info *dev_info)
 | |
| {
 | |
|     JeffLocalObjectRef ref;
 | |
|     AEEBLEDevice dev_struct;
 | |
| 
 | |
|     jeff_runtime_push_local_object_ref(&ref);
 | |
| 
 | |
|     ref.val = jeff_runtime_new_object(class_BLEDevice);
 | |
| 
 | |
|     if (!ref.val) {
 | |
|         jeff_runtime_pop_local_object_ref(1);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     dev_struct = (AEEBLEDevice)(ref.val);
 | |
|     dev_struct->rssi = dev_info->rssi;
 | |
|     dev_struct->mac =
 | |
|         (jbyteArray)jeff_runtime_create_byte_array((int8 *)dev_info->mac, 6);
 | |
| 
 | |
|     app_manager_printf("adv_data_len:%d,scan_response_len:%d\n",
 | |
|                        dev_info->adv_data_len, dev_info->scan_response_len);
 | |
| 
 | |
|     dev_struct->advData = (jbyteArray)jeff_runtime_create_byte_array(
 | |
|         (int8 *)dev_info->adv_data, dev_info->adv_data_len);
 | |
|     dev_struct->scanResponse = (jbyteArray)jeff_runtime_create_byte_array(
 | |
|         (int8 *)dev_info->scan_response, dev_info->scan_response_len);
 | |
|     dev_struct->addressType = dev_info->address_type;
 | |
|     jeff_runtime_initialize_object(ref.val);
 | |
|     jeff_runtime_pop_local_object_ref(1);
 | |
|     if ((dev_struct->mac == NULL) || (dev_struct->advData == NULL)
 | |
|         || (dev_struct->scanResponse == NULL)) {
 | |
|         return NULL;
 | |
|     }
 | |
|     return (AEEBLEDevice)ref.val;
 | |
| }
 | |
| 
 | |
| static void
 | |
| app_instance_process_ble_msg(char *msg)
 | |
| {
 | |
|     bh_queue_ble_sub_msg_t *ble_msg = (bh_queue_ble_sub_msg_t *)msg;
 | |
|     unsigned int argv[5];
 | |
|     uint8 argt[5];
 | |
| 
 | |
|     ble_device_info *dev_info;
 | |
| 
 | |
|     dev_info = (ble_device_info *)ble_msg->payload;
 | |
|     AEEBLEDevice ble_dev;
 | |
| 
 | |
|     argv[0] = (unsigned int)(jbyteArray)jeff_runtime_create_byte_array(
 | |
|         (int8 *)dev_info->mac, 6);
 | |
|     argt[0] = 1;
 | |
|     if (!app_manager_call_java(method_callOnBLEManagerGetBLEDevice, 1, argv,
 | |
|                                argt)) {
 | |
|         app_manager_printf(
 | |
|             "app_manager_call_java BLEManagerGetBLEDevice fail error\n");
 | |
|         goto fail;
 | |
|     }
 | |
|     ble_dev = (AEEBLEDevice)argv[0];
 | |
|     if (ble_dev == NULL) {
 | |
|         ble_dev = create_object_BLEDevice(dev_info);
 | |
|         if (ble_dev == NULL) {
 | |
|             goto fail;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     switch (ble_msg->type) {
 | |
|         case BLE_SUB_EVENT_DISCOVERY:
 | |
|         {
 | |
|             argv[0] = (unsigned int)ble_dev;
 | |
|             argt[0] = 1;
 | |
|             ble_dev->rssi = dev_info->rssi;
 | |
|             if (!app_manager_call_java(method_callOnBLEStartDiscovery, 1, argv,
 | |
|                                        argt)) {
 | |
|                 app_manager_printf(
 | |
|                     "app_manager_call_java method_callOnBLEStartDiscovery "
 | |
|                     "fail error\n");
 | |
|                 goto fail;
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case BLE_SUB_EVENT_CONNECTED:
 | |
|         {
 | |
|             if (ble_dev) {
 | |
|                 argv[0] = (unsigned int)ble_dev;
 | |
|                 argv[1] = 0;
 | |
|                 argt[0] = 1;
 | |
|                 argt[1] = 1;
 | |
|                 if (!app_manager_call_java(method_callOnBLEConnected, 2, argv,
 | |
|                                            argt)) {
 | |
|                     app_manager_printf(
 | |
|                         "app_manager_call_java method_callOnBLEConnected "
 | |
|                         "fail error\n");
 | |
|                     goto fail;
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case BLE_SUB_EVENT_DISCONNECTED:
 | |
|         {
 | |
|             app_manager_printf("app instance received disconnected\n");
 | |
| 
 | |
|             if (ble_dev) {
 | |
|                 argv[0] = (unsigned int)ble_dev;
 | |
|                 argv[1] = 0;
 | |
|                 argt[0] = 1;
 | |
|                 argt[1] = 1;
 | |
|                 ble_dev->rssi = dev_info->rssi;
 | |
|                 if (!app_manager_call_java(method_callOnBLEDisconnected, 2,
 | |
|                                            argv, argt)) {
 | |
|                     app_manager_printf(
 | |
|                         "app_manager_call_java "
 | |
|                         "method_callOnBLEDisconnected fail error\n");
 | |
|                     goto fail;
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case BLE_SUB_EVENT_NOTIFICATION:
 | |
|         {
 | |
|             if (ble_dev) {
 | |
|                 argv[0] = (unsigned int)ble_dev;
 | |
|                 argv[1] =
 | |
|                     (unsigned int)(jbyteArray)jeff_runtime_create_byte_array(
 | |
|                         (int8 *)dev_info->private_data,
 | |
|                         dev_info->private_data_length);
 | |
|                 argv[2] = dev_info->value_handle;
 | |
|                 argv[3] = dev_info->ccc_handle;
 | |
|                 argt[1] = 1;
 | |
|                 argt[2] = 0;
 | |
|                 argt[3] = 0;
 | |
|                 ble_dev->rssi = dev_info->rssi;
 | |
|                 if (!app_manager_call_java(method_callOnBLENotification, 4,
 | |
|                                            argv, argt)) {
 | |
|                     app_manager_printf(
 | |
|                         "app_manager_call_java "
 | |
|                         "method_callOnBLENotification fail error\n");
 | |
|                     goto fail;
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case BLE_SUB_EVENT_INDICATION:
 | |
|         {
 | |
|             if (ble_dev) {
 | |
|                 argv[0] = (unsigned int)ble_dev;
 | |
|                 argv[1] =
 | |
|                     (unsigned int)(jbyteArray)jeff_runtime_create_byte_array(
 | |
|                         (int8 *)dev_info->private_data,
 | |
|                         dev_info->private_data_length);
 | |
|                 argv[2] = dev_info->value_handle;
 | |
|                 argv[3] = dev_info->ccc_handle;
 | |
|                 argt[0] = 1;
 | |
|                 argt[1] = 1;
 | |
|                 argt[2] = 0;
 | |
|                 argt[3] = 0;
 | |
|                 ble_dev->rssi = dev_info->rssi;
 | |
|                 if (!app_manager_call_java(method_callOnBLEIndication, 4, argv,
 | |
|                                            argt)) {
 | |
|                     app_manager_printf(
 | |
|                         "app_manager_call_java method_callOnBLEIndication "
 | |
|                         "fail error\n");
 | |
|                     goto fail;
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case BLE_SUB_EVENT_PASSKEYENTRY:
 | |
|         {
 | |
| 
 | |
|             if (ble_dev) {
 | |
|                 argv[0] = (unsigned int)ble_dev;
 | |
|                 argt[0] = 1;
 | |
|                 argt[1] = 1;
 | |
|                 ble_dev->rssi = dev_info->rssi;
 | |
|                 if (!app_manager_call_java(method_callOnBLEPasskeyEntry, 1,
 | |
|                                            argv, argt)) {
 | |
|                     app_manager_printf(
 | |
|                         "app_manager_call_java "
 | |
|                         "method_callOnBLEPasskeyEntry fail error\n");
 | |
|                     goto fail;
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case BLE_SUB_EVENT_SECURITY_LEVEL_CHANGE:
 | |
|         {
 | |
|             if (ble_dev) {
 | |
|                 ble_dev->securityLevel = dev_info->security_level;
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         default:
 | |
|             break;
 | |
|     }
 | |
| 
 | |
| fail:
 | |
|     if (dev_info->scan_response != NULL) {
 | |
|         APP_MGR_FREE(dev_info->scan_response);
 | |
|     }
 | |
|     if (dev_info->private_data != NULL) {
 | |
|         APP_MGR_FREE(dev_info->private_data);
 | |
|     }
 | |
| 
 | |
|     if (dev_info->adv_data != NULL) {
 | |
|         APP_MGR_FREE(dev_info->adv_data);
 | |
|     }
 | |
|     if (dev_info != NULL) {
 | |
|         APP_MGR_FREE(dev_info);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| app_instance_free_ble_msg(char *msg)
 | |
| {
 | |
|     bh_queue_ble_sub_msg_t *ble_msg = (bh_queue_ble_sub_msg_t *)msg;
 | |
|     ble_device_info *dev_info;
 | |
| 
 | |
|     dev_info = (ble_device_info *)ble_msg->payload;
 | |
| 
 | |
|     if (dev_info->scan_response != NULL)
 | |
|         APP_MGR_FREE(dev_info->scan_response);
 | |
| 
 | |
|     if (dev_info->private_data != NULL)
 | |
|         APP_MGR_FREE(dev_info->private_data);
 | |
| 
 | |
|     if (dev_info->adv_data != NULL)
 | |
|         APP_MGR_FREE(dev_info->adv_data);
 | |
| 
 | |
|     if (dev_info != NULL)
 | |
|         APP_MGR_FREE(dev_info);
 | |
| }
 | |
| 
 | |
| static void
 | |
| app_instance_queue_free_callback(void *queue_msg)
 | |
| {
 | |
|     bh_queue_msg_t *msg = (bh_queue_msg_t *)queue_msg;
 | |
| 
 | |
|     switch (msg->message_type) {
 | |
|         case APPLET_REQUEST:
 | |
|         {
 | |
|             bh_request_msg_t *req_msg = (bh_request_msg_t *)msg->payload;
 | |
|             APP_MGR_FREE(req_msg);
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case TIMER_EVENT:
 | |
|         {
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case SENSOR_EVENT:
 | |
|         {
 | |
|             if (msg->payload) {
 | |
|                 bh_sensor_event_t *sensor_event =
 | |
|                     (bh_sensor_event_t *)msg->payload;
 | |
|                 attr_container_t *event = sensor_event->event;
 | |
| 
 | |
|                 attr_container_destroy(event);
 | |
|                 APP_MGR_FREE(sensor_event);
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case BLE_EVENT:
 | |
|         {
 | |
|             if (msg->payload) {
 | |
|                 app_instance_free_ble_msg(msg->payload);
 | |
|                 APP_MGR_FREE(msg->payload);
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case GPIO_INTERRUPT_EVENT:
 | |
|         {
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         default:
 | |
|         {
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     APP_MGR_FREE(msg);
 | |
| }
 | |
| 
 | |
| static void
 | |
| app_instance_queue_callback(void *queue_msg)
 | |
| {
 | |
|     bh_queue_msg_t *msg = (bh_queue_msg_t *)queue_msg;
 | |
|     unsigned int argv[5];
 | |
|     uint8 argt[5];
 | |
| 
 | |
|     if (app_manager_is_interrupting_module(Module_Jeff)) {
 | |
|         app_instance_queue_free_callback(queue_msg);
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     switch (msg->message_type) {
 | |
|         case APPLET_REQUEST:
 | |
|         {
 | |
|             JeffLocalObjectRef ref;
 | |
|             AEERequest req_obj;
 | |
|             bh_request_msg_t *req_msg = (bh_request_msg_t *)msg->payload;
 | |
|             attr_container_t *attr_cont = (attr_container_t *)req_msg->payload;
 | |
|             module_data *m_data = app_manager_get_module_data(Module_Jeff);
 | |
|             jeff_applet_data *applet_data =
 | |
|                 (jeff_applet_data *)m_data->internal_data;
 | |
| 
 | |
|             app_manager_printf("Applet %s got request, url %s, action %d\n",
 | |
|                                m_data->module_name, req_msg->url,
 | |
|                                req_msg->action);
 | |
| 
 | |
|             /* Create Request object */
 | |
|             req_obj =
 | |
|                 (AEERequest)jeff_object_new(m_data->heap, class_AEERequest);
 | |
|             if (!req_obj) {
 | |
|                 app_manager_printf("Applet process request failed: create "
 | |
|                                    "request obj failed.\n");
 | |
|                 goto fail1;
 | |
|             }
 | |
| 
 | |
|             jeff_runtime_push_local_object_ref(&ref);
 | |
|             ref.val = (JeffObjectRef)req_obj;
 | |
| 
 | |
|             req_obj->mid = req_msg->mid;
 | |
|             req_obj->action = req_msg->action;
 | |
|             req_obj->fmt = req_msg->fmt;
 | |
| 
 | |
|             /* Create Java url string */
 | |
|             if (req_msg->url) {
 | |
|                 req_obj->url =
 | |
|                     (jstring)jeff_runtime_create_java_string(req_msg->url);
 | |
|                 if (!req_obj->url) {
 | |
|                     app_manager_printf("Applet process request failed: "
 | |
|                                        "create url string failed.\n");
 | |
|                     goto fail2;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             /* Create Java AttributeObject payload */
 | |
|             if (attr_cont
 | |
|                 && !attr_container_to_attr_obj(attr_cont, &req_obj->payload)) {
 | |
|                 app_manager_printf("Applet process request failed: convert "
 | |
|                                    "payload failed.\n");
 | |
|                 goto fail2;
 | |
|             }
 | |
| 
 | |
|             /* Call AEEApplet.callOnRequest(Request request) method  */
 | |
|             argv[0] = (unsigned int)applet_data->applet_obj;
 | |
|             argv[1] = (unsigned int)req_obj;
 | |
|             argt[0] = argt[1] = 1;
 | |
|             app_manager_call_java(method_AEEApplet_callOnRequest, 2, argv,
 | |
|                                   argt);
 | |
|             app_manager_printf("Applet process request success.\n");
 | |
| 
 | |
|         fail2:
 | |
|             jeff_runtime_pop_local_object_ref(1);
 | |
|         fail1:
 | |
|             APP_MGR_FREE(req_msg);
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case TIMER_EVENT:
 | |
|         {
 | |
|             if (msg->payload) {
 | |
|                 /* Call Timer.callOnTimer() method */
 | |
|                 argv[0] = (unsigned int)msg->payload;
 | |
|                 argt[0] = 1;
 | |
|                 app_manager_call_java(method_callOnTimer, 1, argv, argt);
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case SENSOR_EVENT:
 | |
|         {
 | |
|             if (msg->payload) {
 | |
|                 bh_sensor_event_t *sensor_event =
 | |
|                     (bh_sensor_event_t *)msg->payload;
 | |
|                 AEESensor sensor = sensor_event->sensor;
 | |
|                 attr_container_t *event = sensor_event->event;
 | |
|                 bool ret = attr_container_to_attr_obj(event, &sensor->event);
 | |
| 
 | |
|                 attr_container_destroy(event);
 | |
|                 APP_MGR_FREE(sensor_event);
 | |
| 
 | |
|                 if (ret) {
 | |
|                     /* Call Sensor.callOnSensorEvent() method */
 | |
|                     argv[0] = (unsigned int)sensor;
 | |
|                     argt[0] = 1;
 | |
|                     app_manager_call_java(method_callOnSensorEvent, 1, argv,
 | |
|                                           argt);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case BLE_EVENT:
 | |
|         {
 | |
|             if (msg->payload) {
 | |
|                 app_instance_process_ble_msg(msg->payload);
 | |
|                 APP_MGR_FREE(msg->payload);
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case GPIO_INTERRUPT_EVENT:
 | |
|         {
 | |
|             AEEGPIOChannel gpio_ch = (AEEGPIOChannel)msg->payload;
 | |
| 
 | |
|             if ((gpio_ch == NULL) || (gpio_ch->callback == 0)
 | |
|                 || (gpio_ch->listener == NULL)) {
 | |
|                 break;
 | |
|             }
 | |
|             argv[0] = (unsigned int)gpio_ch;
 | |
|             argt[0] = 1;
 | |
|             bool ret_value = app_manager_call_java(method_callOnGPIOInterrupt,
 | |
|                                                    1, argv, argt);
 | |
| 
 | |
|             if (!ret_value) {
 | |
|                 app_manager_printf(
 | |
|                     "app_manager_call_java "
 | |
|                     "method_method_callOnGPIOInterrupt return false\n");
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         default:
 | |
|         {
 | |
|             app_manager_printf(
 | |
|                 "Invalid message type of applet queue message.\n");
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     APP_MGR_FREE(msg);
 | |
| }
 | |
| 
 | |
| static JeffClassHeaderLinked *
 | |
| find_main_class(JeffFileHeaderLinked *main_file)
 | |
| {
 | |
|     JeffClassHeaderLinked *c = NULL, *ci;
 | |
|     unsigned int i;
 | |
| 
 | |
|     for (i = 0; i < main_file->internal_class_count; i++) {
 | |
|         ci = main_file->class_header[i];
 | |
| 
 | |
|         if (jeff_is_super_class(class_AEEApplet, ci)
 | |
|             && (ci->access_flag & JEFF_ACC_PUBLIC)) {
 | |
|             if (c) {
 | |
|                 jeff_printe_more_than_one_main_class();
 | |
|                 return NULL;
 | |
|             }
 | |
| 
 | |
|             c = ci;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (!c)
 | |
|         jeff_printe_no_main_class();
 | |
| 
 | |
|     return c;
 | |
| }
 | |
| 
 | |
| /* Java applet thread main routine */
 | |
| static void *
 | |
| app_instance_main(void *arg)
 | |
| {
 | |
|     module_data *m_data = (module_data *)arg;
 | |
|     jeff_applet_data *applet_data = (jeff_applet_data *)m_data->internal_data;
 | |
|     JeffClassHeaderLinked *object_class;
 | |
|     JeffMethodLinked *m;
 | |
|     unsigned int argv[1];
 | |
|     uint8 argt[1];
 | |
| 
 | |
|     app_manager_printf("Java Applet '%s' started\n", m_data->module_name);
 | |
| 
 | |
| #if BEIHAI_ENABLE_TOOL_AGENT != 0
 | |
|     if (applet_data->debug_mode)
 | |
|         jeff_tool_suspend_self();
 | |
| #endif
 | |
| 
 | |
|     applet_data->vm_instance->applet_object = applet_data->applet_obj;
 | |
|     object_class = jeff_object_class_pointer(applet_data->applet_obj);
 | |
|     m = jeff_select_method_virtual(object_class, method_AEEApplet_onInit);
 | |
|     bh_assert(m != NULL);
 | |
|     /* Initialize applet class which call <clinit> */
 | |
|     if (!app_manager_initialize_class(object_class)) {
 | |
|         app_manager_printf("Call <clinit> fail\n");
 | |
|         goto fail;
 | |
|     }
 | |
| 
 | |
|     /* Initialize applet object which call <init> */
 | |
|     if (!app_manager_initialize_object(applet_data->applet_obj)) {
 | |
|         app_manager_printf("Call <init> fail\n");
 | |
|         goto fail;
 | |
|     }
 | |
| 
 | |
|     /* Call applet's onInit() method */
 | |
|     argv[0] = (unsigned int)applet_data->applet_obj;
 | |
|     argt[0] = 1;
 | |
|     if (app_manager_call_java(m, 1, argv, argt))
 | |
|         /* Enter queue loop run to receive and process applet queue message
 | |
|          */
 | |
|         bh_queue_enter_loop_run(m_data->queue, app_instance_queue_callback);
 | |
| 
 | |
| fail:
 | |
|     applet_data->vm_instance->applet_object = applet_data->applet_obj;
 | |
|     object_class = jeff_object_class_pointer(applet_data->applet_obj);
 | |
|     m = jeff_select_method_virtual(object_class, method_AEEApplet_onDestroy);
 | |
|     bh_assert(m != NULL);
 | |
|     /* Call User Applet or AEEApplet onDestroy() method */
 | |
|     app_manager_call_java(m, 1, argv, argt);
 | |
|     if (m != method_AEEApplet_onDestroy) {
 | |
|         /*If 'm' is user onDestroy, then Call AEEApplet.onDestroy() method*/
 | |
|         app_manager_call_java(method_AEEApplet_onDestroy, 1, argv, argt);
 | |
|     }
 | |
|     app_manager_printf("Applet instance main thread exit.\n");
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| static bool
 | |
| verify_signature(JeffFileHeader *file, unsigned size)
 | |
| {
 | |
|     uint8 *sig;
 | |
|     unsigned sig_size;
 | |
| 
 | |
| #if BEIHAI_ENABLE_NO_SIGNATURE != 0
 | |
|     /* no signature */
 | |
|     if (file->file_signature == 0)
 | |
|         return true;
 | |
| #endif
 | |
| 
 | |
|     if (file->file_length != size
 | |
| #if BEIHAI_ENABLE_NO_SIGNATURE == 0
 | |
|         || file->file_signature == 0
 | |
| #endif
 | |
|         || file->file_signature >= file->file_length)
 | |
|         return false;
 | |
| 
 | |
|     sig = (uint8 *)file + file->file_signature;
 | |
|     sig_size = file->file_length - file->file_signature;
 | |
| 
 | |
|     if (0
 | |
|         == app_manager_signature_verify((uint8_t *)file, file->file_signature,
 | |
|                                         sig, sig_size))
 | |
|         return false;
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| /* Install Java Applet */
 | |
| static bool
 | |
| jeff_module_install(bh_request_msg_t *msg)
 | |
| {
 | |
|     unsigned int size, bpk_file_len, main_file_len, heap_size, timeout;
 | |
|     uint8 *bpk_file;
 | |
|     JeffFileHeaderLinked *main_file;
 | |
|     JeffClassHeaderLinked *main_class;
 | |
|     module_data *m_data;
 | |
|     jeff_applet_data *applet_data;
 | |
|     char *applet_name, *applet_perm;
 | |
|     attr_container_t *attr_cont;
 | |
|     bool debug = false;
 | |
| 
 | |
|     /* Check url */
 | |
|     if (!msg->url || strcmp(msg->url, "/applet") != 0) {
 | |
|         SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: invalid url.");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Check payload */
 | |
|     attr_cont = (attr_container_t *)msg->payload;
 | |
|     if (!attr_cont
 | |
|         || !(bpk_file = (uint8 *)attr_container_get_as_bytearray(
 | |
|                  attr_cont, "bpk", &bpk_file_len))) {
 | |
|         SEND_ERR_RESPONSE(msg->mid, "Install Applet failed: invalid bpk file.");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Check applet name */
 | |
|     applet_name = attr_container_get_as_string(attr_cont, "name");
 | |
| 
 | |
|     if (!applet_name || strlen(applet_name) == 0) {
 | |
|         SEND_ERR_RESPONSE(msg->mid,
 | |
|                           "Install Applet failed: invalid applet name.");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (app_manager_lookup_module_data(applet_name)) {
 | |
|         SEND_ERR_RESPONSE(msg->mid,
 | |
|                           "Install Applet failed: applet already installed.");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* TODO: convert bpk file to Jeff file */
 | |
|     main_file_len = bpk_file_len;
 | |
|     main_file = APP_MGR_MALLOC(main_file_len);
 | |
|     if (!main_file) {
 | |
|         SEND_ERR_RESPONSE(msg->mid,
 | |
|                           "Install Applet failed: allocate memory failed.");
 | |
|         return false;
 | |
|     }
 | |
|     bh_memcpy_s(main_file, main_file_len, bpk_file, main_file_len);
 | |
| 
 | |
|     /* Verify signature */
 | |
|     if (!verify_signature((JeffFileHeader *)main_file, main_file_len)) {
 | |
|         SEND_ERR_RESPONSE(
 | |
|             msg->mid,
 | |
|             "Install Applet failed: verify Jeff file signature failed.");
 | |
|         goto fail1;
 | |
|     }
 | |
| 
 | |
|     /* Load Jeff main file */
 | |
|     if (!jeff_runtime_load(main_file, main_file_len, false, NULL, NULL)) {
 | |
|         SEND_ERR_RESPONSE(msg->mid,
 | |
|                           "Install Applet failed: load Jeff file failed.");
 | |
|         goto fail1;
 | |
|     }
 | |
| 
 | |
|     /* Find main class */
 | |
|     main_class = find_main_class(main_file);
 | |
|     if (!main_class) {
 | |
|         SEND_ERR_RESPONSE(msg->mid,
 | |
|                           "Install Applet failed: find applet class failed.");
 | |
|         goto fail2;
 | |
|     }
 | |
| 
 | |
|     /* Create module data */
 | |
|     size = offsetof(module_data, module_name) + strlen(applet_name) + 1;
 | |
|     size = align_uint(size, 4);
 | |
|     m_data = APP_MGR_MALLOC(size + sizeof(jeff_applet_data));
 | |
|     if (!m_data) {
 | |
|         SEND_ERR_RESPONSE(msg->mid,
 | |
|                           "Install Applet failed: allocate memory failed.");
 | |
|         goto fail2;
 | |
|     }
 | |
| 
 | |
|     memset(m_data, 0, size + sizeof(jeff_applet_data));
 | |
|     m_data->module_type = Module_Jeff;
 | |
|     m_data->internal_data = (uint8 *)m_data + size;
 | |
|     applet_data = (jeff_applet_data *)m_data->internal_data;
 | |
|     bh_strcpy_s(m_data->module_name, strlen(applet_name) + 1, applet_name);
 | |
|     applet_data->main_file = main_file;
 | |
| 
 | |
|     /* Set applet execution timeout */
 | |
|     timeout = DEFAULT_APPLET_TIMEOUT;
 | |
|     if (attr_container_contain_key(attr_cont, "execution timeout"))
 | |
|         timeout = attr_container_get_as_int(attr_cont, "execution timeout");
 | |
|     m_data->timeout = timeout;
 | |
| 
 | |
|     /* Create applet permissions */
 | |
|     applet_perm = attr_container_get_as_string(attr_cont, "perm");
 | |
|     if (applet_perm != NULL) {
 | |
|         applet_data->perms = APP_MGR_MALLOC(strlen(applet_perm) + 1);
 | |
|         if (!applet_data->perms) {
 | |
|             SEND_ERR_RESPONSE(msg->mid,
 | |
|                               "Install Applet failed: allocate memory for "
 | |
|                               "applet permissions failed.");
 | |
|             goto fail3;
 | |
|         }
 | |
| 
 | |
|         bh_strcpy_s(applet_data->perms, strlen(applet_perm) + 1, applet_perm);
 | |
|     }
 | |
| 
 | |
|     /* Create applet queue */
 | |
|     m_data->queue = bh_queue_create();
 | |
|     if (!m_data->queue) {
 | |
|         SEND_ERR_RESPONSE(msg->mid,
 | |
|                           "Install Applet failed: create applet queue failed.");
 | |
|         goto fail3_1;
 | |
|     }
 | |
| 
 | |
|     /* Set heap size */
 | |
|     heap_size = DEFAULT_APPLET_HEAP_SIZE;
 | |
|     if (attr_container_contain_key(attr_cont, "heap size")) {
 | |
|         heap_size = attr_container_get_as_int(attr_cont, "heap size");
 | |
|         if (heap_size < MIN_APPLET_HEAP_SIZE)
 | |
|             heap_size = MIN_APPLET_HEAP_SIZE;
 | |
|         else if (heap_size > MAX_APPLET_HEAP_SIZE)
 | |
|             heap_size = MAX_APPLET_HEAP_SIZE;
 | |
|     }
 | |
| 
 | |
|     m_data->heap_size = heap_size;
 | |
| 
 | |
|     /* Create applet heap */
 | |
|     m_data->heap = gc_init_for_instance(heap_size);
 | |
|     if (!m_data->heap) {
 | |
|         SEND_ERR_RESPONSE(msg->mid,
 | |
|                           "Install Applet failed: create heap failed.");
 | |
|         goto fail4;
 | |
|     }
 | |
| 
 | |
|     /* Create applet object */
 | |
|     applet_data->applet_obj = jeff_object_new(m_data->heap, main_class);
 | |
|     if (!applet_data->applet_obj) {
 | |
|         SEND_ERR_RESPONSE(
 | |
|             msg->mid, "Install Applet failed: create applet object failed.");
 | |
|         goto fail5;
 | |
|     }
 | |
| 
 | |
|     /* Initialize watchdog timer */
 | |
|     if (!watchdog_timer_init(m_data)) {
 | |
|         SEND_ERR_RESPONSE(
 | |
|             msg->mid,
 | |
|             "Install Applet failed: create applet watchdog timer failed.");
 | |
|         goto fail5;
 | |
|     }
 | |
| 
 | |
| #if BEIHAI_ENABLE_TOOL_AGENT != 0
 | |
|     /* Check whether applet is debuggable */
 | |
|     if (attr_container_contain_key(attr_cont, "debug"))
 | |
|         debug = attr_container_get_as_bool(attr_cont, "debug");
 | |
| 
 | |
|     applet_data->debug_mode = debug;
 | |
| 
 | |
|     /* Create tool agent queue */
 | |
|     if (debug && !(applet_data->tool_agent_queue = bh_queue_create())) {
 | |
|         SEND_ERR_RESPONSE(
 | |
|             msg->mid, "Install Applet failed: create tool agent queue failed.");
 | |
|         goto fail5_1;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     /* Create applet instance */
 | |
|     applet_data->vm_instance = jeff_runtime_create_instance(
 | |
|         main_file, m_data->heap, 16, app_instance_main, m_data, NULL);
 | |
|     if (!applet_data->vm_instance) {
 | |
|         SEND_ERR_RESPONSE(msg->mid,
 | |
|                           "Install Applet failed: create Java VM failed");
 | |
|         goto fail6;
 | |
|     }
 | |
| 
 | |
|     /* Add applet data to applet data list */
 | |
|     applet_data->vm_instance->applet_object = applet_data->applet_obj;
 | |
|     app_manager_add_module_data(m_data);
 | |
|     app_manager_post_applets_update_event();
 | |
| 
 | |
| #if BEIHAI_ENABLE_TOOL_AGENT != 0
 | |
|     /* Start tool agent thread */
 | |
|     if (debug
 | |
|         && !jeff_tool_start_agent(applet_data->vm_instance,
 | |
|                                   applet_data->tool_agent_queue)) {
 | |
|         SEND_ERR_RESPONSE(msg->mid,
 | |
|                           "Install Applet failed: start tool agent failed");
 | |
|         goto fail6;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     app_manager_printf("Install Applet success!\n");
 | |
|     app_send_response_to_host(msg->mid, CREATED_2_01, NULL); /* CREATED */
 | |
|     return true;
 | |
| 
 | |
| fail6:
 | |
| #if BEIHAI_ENABLE_TOOL_AGENT != 0
 | |
|     if (debug)
 | |
|         bh_queue_destroy(applet_data->tool_agent_queue);
 | |
| #endif
 | |
| 
 | |
| fail5_1:
 | |
|     watchdog_timer_destroy(&m_data->wd_timer);
 | |
| 
 | |
| fail5:
 | |
|     gc_destroy_for_instance(m_data->heap);
 | |
| 
 | |
| fail4:
 | |
|     bh_queue_destroy(m_data->queue, NULL);
 | |
| 
 | |
| fail3_1:
 | |
|     APP_MGR_FREE(applet_data->perms);
 | |
| 
 | |
| fail3:
 | |
|     APP_MGR_FREE(applet_data);
 | |
| 
 | |
| fail2:
 | |
|     jeff_runtime_unload(main_file);
 | |
| 
 | |
| fail1:
 | |
|     APP_MGR_FREE(main_file);
 | |
| 
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| static void
 | |
| cleanup_applet_resource(module_data *m_data)
 | |
| {
 | |
|     jeff_applet_data *applet_data = (jeff_applet_data *)m_data->internal_data;
 | |
| 
 | |
|     /* Unload Jeff main file and free it */
 | |
|     jeff_runtime_unload(applet_data->main_file);
 | |
|     APP_MGR_FREE(applet_data->main_file);
 | |
| 
 | |
|     /* Destroy queue */
 | |
|     bh_queue_destroy(m_data->queue, app_instance_queue_free_callback);
 | |
| 
 | |
|     /* Destroy heap */
 | |
|     gc_destroy_for_instance(m_data->heap);
 | |
| 
 | |
|     /* Destroy watchdog timer */
 | |
|     watchdog_timer_destroy(&m_data->wd_timer);
 | |
| 
 | |
|     /* Remove module data from module data list and free it */
 | |
|     app_manager_del_module_data(m_data);
 | |
|     APP_MGR_FREE(applet_data->perms);
 | |
|     APP_MGR_FREE(m_data);
 | |
| }
 | |
| 
 | |
| /* Uninstall Java Applet */
 | |
| static bool
 | |
| jeff_module_uninstall(bh_request_msg_t *msg)
 | |
| {
 | |
|     module_data *m_data;
 | |
|     jeff_applet_data *applet_data;
 | |
|     attr_container_t *attr_cont;
 | |
|     char *applet_name;
 | |
|     bool do_not_reply = false;
 | |
| 
 | |
|     /* Check payload and applet name*/
 | |
|     attr_cont = (attr_container_t *)msg->payload;
 | |
| 
 | |
|     /* Check whether need to reply this request */
 | |
|     if (attr_container_contain_key(attr_cont, "do not reply me"))
 | |
|         do_not_reply = attr_container_get_as_bool(attr_cont, "do not reply me");
 | |
| 
 | |
|     /* Check url */
 | |
|     if (!msg->url || strcmp(msg->url, "/applet") != 0) {
 | |
|         if (!do_not_reply)
 | |
|             SEND_ERR_RESPONSE(msg->mid,
 | |
|                               "Uninstall Applet failed: invalid url.");
 | |
|         else
 | |
|             app_manager_printf("Uninstall Applet failed: invalid url.");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (!attr_cont
 | |
|         || !(applet_name = attr_container_get_as_string(attr_cont, "name"))
 | |
|         || strlen(applet_name) == 0) {
 | |
|         if (!do_not_reply)
 | |
|             SEND_ERR_RESPONSE(msg->mid,
 | |
|                               "Uninstall Applet failed: invalid applet name.");
 | |
|         else
 | |
|             app_manager_printf("Uninstall Applet failed: invalid applet name.");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     m_data = app_manager_lookup_module_data(applet_name);
 | |
|     if (!m_data) {
 | |
|         if (!do_not_reply)
 | |
|             SEND_ERR_RESPONSE(msg->mid,
 | |
|                               "Uninstall Applet failed: no applet found.");
 | |
|         else
 | |
|             app_manager_printf("Uninstall Applet failed: no applet found.");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (m_data->module_type != Module_Jeff) {
 | |
|         if (!do_not_reply)
 | |
|             SEND_ERR_RESPONSE(msg->mid,
 | |
|                               "Uninstall Applet failed: invlaid module type.");
 | |
|         else
 | |
|             app_manager_printf("Uninstall Applet failed: invalid module type.");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (m_data->wd_timer.is_interrupting) {
 | |
|         if (!do_not_reply)
 | |
|             SEND_ERR_RESPONSE(msg->mid,
 | |
|                               "Uninstall Applet failed: applet is being "
 | |
|                               "interrupted by watchdog.");
 | |
|         else
 | |
|             app_manager_printf("Uninstall Applet failed: applet is being "
 | |
|                                "interrupted by watchdog.");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Exit applet queue loop run */
 | |
|     bh_queue_exit_loop_run(m_data->queue);
 | |
| 
 | |
|     applet_data = (jeff_applet_data *)m_data->internal_data;
 | |
| #if BEIHAI_ENABLE_TOOL_AGENT != 0
 | |
|     /* Exit tool agent queue loop run */
 | |
|     if (is_tool_agent_running(m_data)) {
 | |
|         bh_queue_exit_loop_run(applet_data->tool_agent_queue);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     /* Wait the end of the applet instance and then destroy it */
 | |
|     if (applet_data->vm_instance->main_file)
 | |
|         jeff_runtime_wait_for_instance(applet_data->vm_instance, -1);
 | |
|     jeff_runtime_destroy_instance(applet_data->vm_instance);
 | |
| 
 | |
|     cleanup_applet_resource(m_data);
 | |
|     app_manager_post_applets_update_event();
 | |
| 
 | |
|     app_manager_printf("Uninstall Applet success!\n");
 | |
| 
 | |
|     if (!do_not_reply)
 | |
|         app_send_response_to_host(msg->mid, DELETED_2_02, NULL); /* DELETED */
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| #define PERM_PREFIX "AEE.permission."
 | |
| 
 | |
| static bool
 | |
| check_permission_format(const char *perm)
 | |
| {
 | |
|     const char *prefix = PERM_PREFIX;
 | |
|     const char *p;
 | |
| 
 | |
|     if (perm == NULL || strncmp(perm, prefix, strlen(prefix)) != 0
 | |
|         || *(p = perm + strlen(prefix)) == '\0')
 | |
|         return false;
 | |
| 
 | |
|     do {
 | |
|         if (!(*p == '.' || ('A' <= *p && *p <= 'Z')
 | |
|               || ('a' <= *p && *p <= 'z')))
 | |
|             return false;
 | |
|     } while (*++p != '\0');
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| static bool
 | |
| match(const char *haystack, const char *needle, char delim)
 | |
| {
 | |
|     const char *p = needle;
 | |
| 
 | |
|     if (haystack == NULL || *haystack == '\0' || needle == NULL
 | |
|         || *needle == '\0')
 | |
|         return false;
 | |
| 
 | |
|     while (true) {
 | |
|         while (true) {
 | |
|             if ((*haystack == '\0' || *haystack == delim) && *p == '\0') {
 | |
|                 return true;
 | |
|             }
 | |
|             else if (*p == *haystack) {
 | |
|                 ++p;
 | |
|                 ++haystack;
 | |
|             }
 | |
|             else {
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         while (*haystack != '\0' && *haystack != delim) {
 | |
|             ++haystack;
 | |
|         }
 | |
|         if (*haystack == '\0') {
 | |
|             return false;
 | |
|         }
 | |
|         else {
 | |
|             ++haystack;
 | |
|             p = needle;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| bool
 | |
| bh_applet_check_permission(const char *perm)
 | |
| {
 | |
|     return check_permission_format(perm)
 | |
|            && match(app_manager_get_jeff_applet_data()->perms,
 | |
|                     perm + strlen(PERM_PREFIX), ' ');
 | |
| }
 | |
| 
 | |
| static bool
 | |
| jeff_module_init()
 | |
| {
 | |
|     JeffDescriptorFull d[] = { { JEFF_TYPE_VOID, 0, NULL } };
 | |
|     JeffDescriptorFull d1[] = { { JEFF_TYPE_OBJECT | JEFF_TYPE_REF, 0, NULL },
 | |
|                                 { JEFF_TYPE_VOID, 0, NULL } };
 | |
| 
 | |
|     /* Resolve class com.intel.aee.AEEApplet */
 | |
|     class_AEEApplet =
 | |
|         jeff_runtime_resolve_class_full_name("com.intel.aee.AEEApplet");
 | |
|     if (!class_AEEApplet) {
 | |
|         app_manager_printf(
 | |
|             "App Manager start failed: resolve class AEEApplet failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resolve class com.intel.aee.Request */
 | |
|     class_AEERequest =
 | |
|         jeff_runtime_resolve_class_full_name("com.intel.aee.Request");
 | |
|     if (!class_AEERequest) {
 | |
|         app_manager_printf(
 | |
|             "App Manager start failed: resolve class Request failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resolve class com.intel.aee.Timer */
 | |
|     class_Timer = jeff_runtime_resolve_class_full_name("com.intel.aee.Timer");
 | |
|     if (!class_Timer) {
 | |
|         app_manager_printf(
 | |
|             "App Manager start failed: resolve class Timer failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resolve class com.intel.aee.Sensor */
 | |
|     class_Sensor = jeff_runtime_resolve_class_full_name("com.intel.aee.Sensor");
 | |
|     if (!class_Sensor) {
 | |
|         app_manager_printf(
 | |
|             "App Manager start failed: resolve class Sensor failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resolve class com.intel.aee.ble.BLEManager */
 | |
|     class_BLEManager =
 | |
|         jeff_runtime_resolve_class_full_name("com.intel.aee.ble.BLEManager");
 | |
|     if (!class_BLEManager) {
 | |
|         app_manager_printf(
 | |
|             "App Manager start failed: resolve class BLEManager failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resolve class com.intel.aee.ble.BLEDevice */
 | |
|     class_BLEDevice =
 | |
|         jeff_runtime_resolve_class_full_name("com.intel.aee.ble.BLEDevice");
 | |
|     if (!class_BLEDevice) {
 | |
|         app_manager_printf(
 | |
|             "App Manager start failed: resolve class BLEDevice failed.\n");
 | |
|         return false;
 | |
|     }
 | |
|     /* Resolve class com.intel.aee.ble.BLEDevice */
 | |
|     class_BLEGattService = jeff_runtime_resolve_class_full_name(
 | |
|         "com.intel.aee.ble.BLEGattService");
 | |
|     if (!class_BLEGattService) {
 | |
|         app_manager_printf("App Manager start failed: resolve class "
 | |
|                            "BLEGattService failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resolve class com.intel.aee.ble.BLEDevice */
 | |
|     class_BLEGattCharacteristic = jeff_runtime_resolve_class_full_name(
 | |
|         "com.intel.aee.ble.BLEGattCharacteristic");
 | |
|     if (!class_BLEGattCharacteristic) {
 | |
|         app_manager_printf("App Manager start failed: resolve class "
 | |
|                            "BLEGattCharacteristic failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resolve class com.intel.aee.ble.BLEDevice */
 | |
|     class_BLEGattDescriptor = jeff_runtime_resolve_class_full_name(
 | |
|         "com.intel.aee.ble.BLEGattDescriptor");
 | |
|     if (!class_BLEGattDescriptor) {
 | |
|         app_manager_printf("App Manager start failed: resolve class "
 | |
|                            "BLEGattDescriptor failed.\n");
 | |
|         return false;
 | |
|     }
 | |
|     /* Resolve class com.intel.aee.gpio.GPIOChannel */
 | |
|     class_GPIOChannel =
 | |
|         jeff_runtime_resolve_class_full_name("com.intel.aee.gpio.GPIOChannel");
 | |
|     if (!class_GPIOChannel) {
 | |
|         app_manager_printf("App Manager start failed: resolve class "
 | |
|                            "GPIOChannel failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resolve method com.intel.aee.AEEApplet.onInit() */
 | |
|     method_AEEApplet_onInit =
 | |
|         jeff_lookup_method(class_AEEApplet, "onInit", 0, d);
 | |
|     if (!method_AEEApplet_onInit) {
 | |
|         app_manager_printf("App Manager start failed: resolve method "
 | |
|                            "Applet.onInit() failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resolve method com.intel.aee.AEEApplet.onDestroy() */
 | |
|     method_AEEApplet_onDestroy =
 | |
|         jeff_lookup_method(class_AEEApplet, "onDestroy", 0, d);
 | |
|     if (!method_AEEApplet_onDestroy) {
 | |
|         app_manager_printf("App Manager start failed: resolve method "
 | |
|                            "AEEApplet.onDestroy() failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resolve method com.intel.aee.AEEApplet.callOnRequest(Request) */
 | |
|     d1[0].class_header = class_AEERequest;
 | |
|     method_AEEApplet_callOnRequest =
 | |
|         jeff_lookup_method(class_AEEApplet, "callOnRequest", 1, d1);
 | |
|     if (!method_AEEApplet_callOnRequest) {
 | |
|         app_manager_printf("App Manager start failed: resolve method "
 | |
|                            "AEEApplet.callOnRequest() failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resolve method com.intel.aee.Timer.callOnTimer() */
 | |
|     method_callOnTimer = jeff_lookup_method(class_Timer, "callOnTimer", 0, d);
 | |
|     if (!method_callOnTimer) {
 | |
|         app_manager_printf("App Manager start failed: resolve method "
 | |
|                            "Timer.callOnTimer() failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resolve method com.intel.aee.Sensor.callOnSensorEvent() */
 | |
|     method_callOnSensorEvent =
 | |
|         jeff_lookup_method(class_Sensor, "callOnSensorEvent", 0, d);
 | |
|     if (!method_callOnSensorEvent) {
 | |
|         app_manager_printf("App Manager start failed: resolve method "
 | |
|                            "Sensor.callOnSensorEvent() failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resovle method
 | |
|      * com.intel.aee.ble.BLEManager.callOnBLEStartDiscovery(BLEDevice) */
 | |
|     d1[0].class_header = class_BLEDevice;
 | |
|     method_callOnBLEStartDiscovery =
 | |
|         jeff_lookup_method(class_BLEManager, "callOnBLEStartDiscovery", 1, d1);
 | |
|     if (!method_callOnBLEStartDiscovery) {
 | |
|         app_manager_printf("App Manager start failed: resolve method "
 | |
|                            "BLEManager.callOnBLEStartDiscovery() failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resovle method
 | |
|      * com.intel.aee.ble.BLEManager.callOnBLEConnected(BLEDevice) */
 | |
|     JeffDescriptorFull d2_1[] = { { JEFF_TYPE_OBJECT | JEFF_TYPE_REF, 0,
 | |
|                                     class_BLEDevice },
 | |
|                                   { JEFF_TYPE_INT, 0, NULL },
 | |
|                                   { JEFF_TYPE_VOID, 0, NULL } };
 | |
|     method_callOnBLEConnected =
 | |
|         jeff_lookup_method(class_BLEManager, "callOnBLEConnected", 2, d2_1);
 | |
|     if (!method_callOnBLEConnected) {
 | |
|         app_manager_printf("App Manager start failed: resolve method "
 | |
|                            "BLEManager.callOnBLEConnected() failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resovle method
 | |
|      * com.intel.aee.ble.BLEManager.method_callOnBLENotification(BLEDevice,byte[])
 | |
|      */
 | |
|     JeffDescriptorFull d2_2[] = {
 | |
|         { JEFF_TYPE_OBJECT | JEFF_TYPE_REF, 0, class_BLEDevice },
 | |
|         { JEFF_TYPE_BYTE | JEFF_TYPE_REF | JEFF_TYPE_MONO, 1, NULL },
 | |
|         { JEFF_TYPE_INT, 0, NULL },
 | |
|         { JEFF_TYPE_INT, 0, NULL },
 | |
|         { JEFF_TYPE_VOID, 0, NULL }
 | |
|     };
 | |
|     method_callOnBLENotification =
 | |
|         jeff_lookup_method(class_BLEManager, "callOnBLENotification", 4, d2_2);
 | |
|     if (!method_callOnBLENotification) {
 | |
|         app_manager_printf("App Manager start failed: resolve method "
 | |
|                            "BLEManager.callOnBLENotification() failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resovle method
 | |
|      * com.intel.aee.ble.BLEManager.callOnBLEConnected(BLEDevice,byte[]) */
 | |
|     method_callOnBLEIndication =
 | |
|         jeff_lookup_method(class_BLEManager, "callOnBLEIndication", 4, d2_2);
 | |
|     if (!method_callOnBLEIndication) {
 | |
|         app_manager_printf("App Manager start failed: resolve method "
 | |
|                            "BLEManager.callOnBLEIndication() failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resovle method
 | |
|      * com.intel.aee.ble.BLEManager.callOnBLEConnected(BLEDevice) */
 | |
|     d1[0].class_header = class_BLEDevice;
 | |
|     method_callOnBLEDisconnected =
 | |
|         jeff_lookup_method(class_BLEManager, "callOnBLEDisconnected", 1, d1);
 | |
|     if (!method_callOnBLEDisconnected) {
 | |
|         app_manager_printf("App Manager start failed: resolve method "
 | |
|                            "BLEManager.callOnBLEDisconnected() failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /* Resovle method
 | |
|      * com.intel.aee.ble.BLEManager.callOnBLEConnected(BLEDevice) */
 | |
|     method_callOnBLEPasskeyEntry =
 | |
|         jeff_lookup_method(class_BLEManager, "callOnBLEPasskeyEntry", 1, d1);
 | |
|     if (!method_callOnBLEPasskeyEntry) {
 | |
|         app_manager_printf("App Manager start failed: resolve method "
 | |
|                            "BLEManager.callOnBLEPasskeyEntry() failed.\n");
 | |
|         return false;
 | |
|     }
 | |
|     /* Resovle  method void
 | |
|      * com.intel.aee.gpio.GPIOChannel.callOnGPIOInterrupt()  */
 | |
|     method_callOnGPIOInterrupt =
 | |
|         jeff_lookup_method(class_GPIOChannel, "callOnGPIOInterrupt", 0, d);
 | |
|     if (!method_callOnGPIOInterrupt) {
 | |
|         app_manager_printf("App Manager start failed: resolve method "
 | |
|                            "GPIOChannel.callOnGPIOInterrupt() failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     JeffDescriptorFull d2[] = {
 | |
|         { JEFF_TYPE_BYTE | JEFF_TYPE_REF | JEFF_TYPE_MONO, 1, NULL },
 | |
|         { JEFF_TYPE_OBJECT | JEFF_TYPE_REF, 0, class_BLEDevice }
 | |
|     };
 | |
|     /* Resovle method com.intel.aee.ble.BLEManager.getBLEDevice(byte []) */
 | |
|     method_callOnBLEManagerGetBLEDevice =
 | |
|         jeff_lookup_method(class_BLEManager, "getBLEDevice", 1, d2);
 | |
|     if (!method_callOnBLEManagerGetBLEDevice) {
 | |
|         app_manager_printf("App Manager start failed: resolve method "
 | |
|                            "BLEManager.getBLEDevice() failed.\n");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| static void
 | |
| jeff_module_watchdog_kill(module_data *m_data)
 | |
| {
 | |
|     jeff_applet_data *applet_data = (jeff_applet_data *)m_data->internal_data;
 | |
| 
 | |
|     app_manager_printf("Watchdog interrupt the applet %s\n",
 | |
|                        m_data->module_name);
 | |
| 
 | |
|     jeff_runtime_interrupt_instance(applet_data->vm_instance, true);
 | |
| 
 | |
|     /* Exit applet queue loop run */
 | |
|     bh_queue_exit_loop_run(m_data->queue);
 | |
| 
 | |
|     /* Wait the end of the applet instance. If timeout, it means applet
 | |
|      * is busy executing native code, then try to cancle the main thread. */
 | |
|     if (applet_data->vm_instance->main_file)
 | |
|         jeff_runtime_wait_for_instance(applet_data->vm_instance, 3000);
 | |
| 
 | |
|     if (applet_data->vm_instance->main_file) {
 | |
|         app_manager_printf("Watchdog cancel applet main thread.\n");
 | |
|         os_thread_cancel(applet_data->vm_instance->main_tlr.handle);
 | |
|         /* k_thread_abort(applet_data->vm_instance->main_tlr.handle); */
 | |
|     }
 | |
| 
 | |
|     send_exception_event_to_host(m_data->module_name,
 | |
|                                  "java.lang.InterruptedException");
 | |
|     cleanup_applet_resource(m_data);
 | |
|     app_manager_printf("Watchdog interrupt Jeff applet done.\n");
 | |
| }
 | |
| 
 | |
| static bool
 | |
| jeff_module_handle_host_url(void *queue_msg)
 | |
| {
 | |
| #if BEIHAI_ENABLE_TOOL_AGENT != 0
 | |
|     bh_queue_msg_t *msg = (bh_queue_msg_t *)queue_msg;
 | |
| 
 | |
|     if (msg->message_type == COAP_PARSED) {
 | |
|         coap_packet_t *packet = (coap_packet_t *)msg->payload;
 | |
|         attr_container_t *attr_cont = (attr_container_t *)packet->payload;
 | |
|         const char *url = NULL;
 | |
|         int url_len = 0, mid;
 | |
| 
 | |
|         bh_memcpy_s(&mid, sizeof(uint32), packet->token, sizeof(uint32));
 | |
|         url_len = coap_get_header_uri_path(packet, &url);
 | |
| 
 | |
|         /* Send request to tool agent */
 | |
|         if (url_len >= 12 && memcmp(url, "/tool_agent/", 12) == 0) {
 | |
|             module_data *m_data;
 | |
|             jeff_applet_data *applet_data;
 | |
|             unsigned attr_cont_len = 0, req_msg_len;
 | |
|             bh_queue_msg_t *tool_agent_msg;
 | |
|             bh_request_msg_t *req_msg;
 | |
|             char url_buf[256] = { 0 }, *p = url_buf;
 | |
|             char applet_name[128] = { 0 };
 | |
| 
 | |
|             /* Resolve applet name */
 | |
|             bh_memcpy_s(url_buf, sizeof(url_buf), url + 12, url_len - 12);
 | |
|             while (*p != '/' && *p != '\0')
 | |
|                 p++;
 | |
| 
 | |
|             bh_memcpy_s(applet_name, sizeof(applet_name), url_buf, p - url_buf);
 | |
|             app_manager_printf("Send request to tool agent of applet: %s\n",
 | |
|                                applet_name);
 | |
| 
 | |
|             /* Check applet name */
 | |
|             if (!(m_data = app_manager_lookup_module_data(applet_name))) {
 | |
|                 SEND_ERR_RESPONSE(mid, "Send request to tool agent failed: "
 | |
|                                        "invalid applet name");
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             applet_data = (jeff_applet_data *)m_data->internal_data;
 | |
|             /* Attach debug: start the tool agent firstly */
 | |
|             if (packet->code == COAP_PUT) {
 | |
|                 if (is_tool_agent_running(m_data)) {
 | |
|                     SEND_ERR_RESPONSE(mid, "Attach debug failed: tool "
 | |
|                                            "agent is already exist.");
 | |
|                     return false;
 | |
|                 }
 | |
| 
 | |
|                 applet_data->debug_mode = true;
 | |
| 
 | |
|                 /* Create tool agent queue */
 | |
|                 if (!(applet_data->tool_agent_queue = bh_queue_create())) {
 | |
|                     SEND_ERR_RESPONSE(mid, "Attach debug failed: create "
 | |
|                                            "tool agent queue failed.");
 | |
|                     return false;
 | |
|                 }
 | |
| 
 | |
|                 /* Start tool agent thread */
 | |
|                 if (!jeff_tool_start_agent(applet_data->vm_instance,
 | |
|                                            applet_data->tool_agent_queue)) {
 | |
|                     bh_queue_destroy(applet_data->tool_agent_queue, NULL);
 | |
|                     SEND_ERR_RESPONSE(
 | |
|                         mid, "Attach debug failed: start tool agent failed");
 | |
|                     return false;
 | |
|                 }
 | |
| 
 | |
|                 app_manager_printf("Attach debug: start tool agent of "
 | |
|                                    "applet %s success.\n",
 | |
|                                    applet_name);
 | |
|                 app_send_response_to_host(mid, CREATED_2_01, NULL); /* OK */
 | |
|             }
 | |
|             else {
 | |
|                 /* Check tool agent running */
 | |
|                 if (!is_tool_agent_running(m_data)) {
 | |
|                     SEND_ERR_RESPONSE(mid, "Send request to tool agent failed: "
 | |
|                                            "tool agent is not running");
 | |
|                     return false;
 | |
|                 }
 | |
| 
 | |
|                 /* Create queue message for tool agent */
 | |
|                 if (!(tool_agent_msg =
 | |
|                           APP_MGR_MALLOC(sizeof(bh_queue_msg_t)))) {
 | |
|                     SEND_ERR_RESPONSE(mid, "Send request to tool agent failed: "
 | |
|                                            "allocate memory failed");
 | |
|                     return false;
 | |
|                 }
 | |
| 
 | |
|                 if (attr_cont)
 | |
|                     attr_cont_len =
 | |
|                         attr_container_get_serialize_length(attr_cont);
 | |
| 
 | |
|                 req_msg_len =
 | |
|                     sizeof(bh_request_msg_t) + strlen(p) + 1 + attr_cont_len;
 | |
| 
 | |
|                 /* Create request message */
 | |
|                 if (!(req_msg = APP_MGR_MALLOC(req_msg_len))) {
 | |
|                     SEND_ERR_RESPONSE(mid, "Send request to applet failed: "
 | |
|                                            "allocate memory failed");
 | |
|                     APP_MGR_FREE(tool_agent_msg);
 | |
|                     return false;
 | |
|                 }
 | |
| 
 | |
|                 /* Set request message */
 | |
|                 memset(req_msg, 0, req_msg_len);
 | |
|                 req_msg->mid = mid;
 | |
|                 req_msg->url = (char *)req_msg + sizeof(bh_request_msg_t);
 | |
|                 bh_strcpy_s(req_msg->url, strlen(p) + 1,
 | |
|                             p); /* Actual url sent to tool agent */
 | |
|                 req_msg->action = packet->code;
 | |
|                 req_msg->fmt = 0;
 | |
|                 if (attr_cont) {
 | |
|                     req_msg->payload = (char *)req_msg
 | |
|                                        + sizeof(bh_request_msg_t) + strlen(p)
 | |
|                                        + 1;
 | |
|                     attr_container_serialize(req_msg->payload, attr_cont);
 | |
|                 }
 | |
| 
 | |
|                 /* Set queue message and send to tool agent's queue */
 | |
|                 tool_agent_msg->message_type = JDWP_REQUEST;
 | |
|                 tool_agent_msg->payload_size = req_msg_len;
 | |
|                 tool_agent_msg->payload = (char *)req_msg;
 | |
|                 if (!bh_queue_send_message(applet_data->tool_agent_queue,
 | |
|                                            tool_agent_msg)) {
 | |
|                     APP_MGR_FREE(req_msg);
 | |
|                     APP_MGR_FREE(tool_agent_msg);
 | |
|                     SEND_ERR_RESPONSE(mid, "Send request to tool agent failed: "
 | |
|                                            "send queue msg failed.");
 | |
|                     return false;
 | |
|                 }
 | |
| 
 | |
|                 /* app_manager_printf("Send request to tool agent of applet
 | |
|                  * %s success.\n", applet_name); */
 | |
|             }
 | |
| 
 | |
|             return true;
 | |
|         }
 | |
|     }
 | |
| #endif /* BEIHAI_ENABLE_TOOL_AGENT != 0 */
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| static module_data *
 | |
| jeff_module_get_module_data(void)
 | |
| {
 | |
|     JeffThreadLocalRoot *self = jeff_runtime_get_tlr();
 | |
|     return (module_data *)self->il_root->start_routine_arg;
 | |
| }
 | |
| 
 | |
| #if BEIHAI_ENABLE_TOOL_AGENT != 0
 | |
| 
 | |
| #define JDWP_HANDSHAKE_MAGIC "JDWP-Handshake"
 | |
| #define JDWP_HANDSHAKE_LEN (sizeof(JDWP_HANDSHAKE_MAGIC) - 1)
 | |
| 
 | |
| #define JDWP_PAYLOAD_KEY "jdwp"
 | |
| 
 | |
| static bool debug = true;
 | |
| 
 | |
| static bool
 | |
| send_msg_to_host(int mid, const char *url, int code, const uint8 *msg,
 | |
|                  unsigned size)
 | |
| {
 | |
|     bool ret;
 | |
|     int payload_len = 0;
 | |
|     attr_container_t *payload = NULL;
 | |
| 
 | |
|     if (msg) {
 | |
|         if ((payload = attr_container_create(""))) {
 | |
|             attr_container_set_bytearray(&payload, JDWP_PAYLOAD_KEY,
 | |
|                                          (const int8_t *)msg, size);
 | |
|             payload_len = attr_container_get_serialize_length(payload);
 | |
|         }
 | |
|     }
 | |
|     ret = app_send_msg_to_host(mid, url, code, (char *)payload, payload_len);
 | |
| 
 | |
|     if (payload)
 | |
|         attr_container_destroy(payload);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static bool
 | |
| send_response(int mid, int code, const uint8 *msg, unsigned size)
 | |
| {
 | |
|     return send_msg_to_host(mid, NULL, code, msg, size);
 | |
| }
 | |
| 
 | |
| static bool
 | |
| send_packet_response(int mid, int code, JeffBuffer *packet)
 | |
| {
 | |
|     int size;
 | |
| 
 | |
|     if ((size = jeff_buffer_size(packet)) == 0)
 | |
|         /* No data need to be written, succeed.  */
 | |
|         return true;
 | |
| 
 | |
|     return send_msg_to_host(mid, NULL, code, jeff_buffer_at(packet, 0), size);
 | |
| }
 | |
| 
 | |
| void
 | |
| jeff_tool_event_publish(uint8 *evtbuf, unsigned size)
 | |
| {
 | |
|     char *prefix = "/jdwp/", *url = NULL;
 | |
|     int url_len;
 | |
| 
 | |
|     url_len = strlen(prefix) + strlen(app_manager_get_module_name(Module_Jeff));
 | |
|     if (NULL == (url = jeff_runtime_malloc(url_len + 1)))
 | |
|         return;
 | |
| 
 | |
|     bh_strcpy_s(url, url_len + 1, prefix);
 | |
|     bh_strcat_s(url, url_len + 1, app_manager_get_module_name(Module_Jeff));
 | |
| 
 | |
|     /* Event is sent as request so we set code as COAP_PUT */
 | |
|     if (event_is_registered(url))
 | |
|         send_msg_to_host(0, url, COAP_PUT, evtbuf, size);
 | |
| 
 | |
|     jeff_runtime_free(url);
 | |
| }
 | |
| 
 | |
| #define SEND_ERROR_RESPONSE(err_msg)                            \
 | |
|     do {                                                        \
 | |
|         app_manager_printf("%s\n", err_msg);                    \
 | |
|         send_response(req_msg->mid, INTERNAL_SERVER_ERROR_5_00, \
 | |
|                       (uint8 *)err_msg, strlen(err_msg) + 1);   \
 | |
|     } while (0)
 | |
| 
 | |
| /* Queue callback of tool agent */
 | |
| void
 | |
| tool_agent_queue_callback(void *arg)
 | |
| {
 | |
|     bh_queue_msg_t *msg = (bh_queue_msg_t *)arg;
 | |
| 
 | |
|     if (msg->message_type == JDWP_REQUEST) {
 | |
|         bh_request_msg_t *req_msg = (bh_request_msg_t *)msg->payload;
 | |
|         attr_container_t *attr_cont = (attr_container_t *)req_msg->payload;
 | |
|         JeffThreadLocalRoot *self = jeff_runtime_get_tlr();
 | |
|         JeffInstanceLocalRoot *cur_instance = self->il_root;
 | |
|         JeffToolAgent *agent = cur_instance->tool_agent;
 | |
|         bh_queue *queue = (bh_queue *)self->start_routine_arg;
 | |
| 
 | |
|         if (debug)
 | |
|             app_manager_printf(
 | |
|                 "Tool Agent of applet %s got request, url %s, action %d\n",
 | |
|                 app_manager_get_module_name(Module_Jeff), req_msg->url,
 | |
|                 req_msg->action);
 | |
| 
 | |
|         /* Handshake or Process Request */
 | |
|         if (req_msg->action == COAP_GET) {
 | |
|             uint8 *buf;
 | |
|             unsigned buf_len;
 | |
| 
 | |
|             if (!attr_cont
 | |
|                 || !(buf = (uint8 *)attr_container_get_as_bytearray(
 | |
|                          attr_cont, JDWP_PAYLOAD_KEY, &buf_len))) {
 | |
|                 SEND_ERROR_RESPONSE("Tool Agent fail: invalid JDWP payload.");
 | |
|                 goto fail;
 | |
|             }
 | |
| 
 | |
|             if (!agent->connected) {
 | |
|                 if (buf_len != JDWP_HANDSHAKE_LEN
 | |
|                     || memcmp(buf, JDWP_HANDSHAKE_MAGIC, JDWP_HANDSHAKE_LEN)) {
 | |
|                     SEND_ERROR_RESPONSE("Tool Agent fail: handshake fail.");
 | |
|                     goto fail;
 | |
|                 }
 | |
| 
 | |
|                 /* Handshake success and response */
 | |
|                 agent->connected = true;
 | |
|                 send_response(req_msg->mid, CONTENT_2_05, buf, buf_len);
 | |
|             }
 | |
|             else {
 | |
|                 /* TODO: tool-agent thread should reuse the request/reply
 | |
|                  * buffer to avoid allocating memory repeatedly */
 | |
|                 JeffBuffer request, reply;
 | |
| 
 | |
|                 /* Initialize the package buffers. */
 | |
|                 jeff_buffer_init(&request);
 | |
|                 jeff_buffer_init(&reply);
 | |
| 
 | |
|                 if (!jeff_buffer_resize(&request, buf_len)) {
 | |
|                     SEND_ERROR_RESPONSE("Tool Agent fail: resize buffer fail.");
 | |
|                     jeff_buffer_destroy(&request);
 | |
|                     jeff_buffer_destroy(&reply);
 | |
|                     goto fail;
 | |
|                 }
 | |
| 
 | |
|                 /* Copy data from request to jeff buffer */
 | |
|                 bh_memcpy_s(jeff_buffer_at(&request, 0),
 | |
|                             jeff_buffer_size(&request), buf, buf_len);
 | |
| 
 | |
|                 /* Handle JDWP request */
 | |
|                 if (!jeff_tool_handle_packet(agent, &request, &reply)) {
 | |
|                     SEND_ERROR_RESPONSE(
 | |
|                         "Tool agent fail: handle request fail.");
 | |
|                     jeff_buffer_destroy(&request);
 | |
|                     jeff_buffer_destroy(&reply);
 | |
|                     goto fail;
 | |
|                 }
 | |
| 
 | |
|                 /* Response JDWP reply */
 | |
|                 send_packet_response(req_msg->mid, CONTENT_2_05, &reply);
 | |
| 
 | |
|                 /* Destroy the package buffers. */
 | |
|                 jeff_buffer_destroy(&request);
 | |
|                 jeff_buffer_destroy(&reply);
 | |
|             }
 | |
|         }
 | |
|         /* Debugger disconnect */
 | |
|         else if (req_msg->action == COAP_DELETE) {
 | |
|             send_response(req_msg->mid, DELETED_2_02, NULL, 0);
 | |
|             bh_queue_exit_loop_run(queue);
 | |
|         }
 | |
|         else {
 | |
|             SEND_ERROR_RESPONSE("Tool agent fail: invalid request.");
 | |
|             goto fail;
 | |
|         }
 | |
| 
 | |
|         APP_MGR_FREE(req_msg);
 | |
|         APP_MGR_FREE(msg);
 | |
|         return;
 | |
| 
 | |
|     fail:
 | |
|         bh_queue_exit_loop_run(queue);
 | |
|         APP_MGR_FREE(req_msg);
 | |
|     }
 | |
| 
 | |
|     APP_MGR_FREE(msg);
 | |
| }
 | |
| 
 | |
| void
 | |
| tool_agent_queue_free_callback(void *message)
 | |
| {
 | |
|     bh_queue_msg_t *msg = (bh_queue_msg_t *)message;
 | |
| 
 | |
|     if (msg->message_type == JDWP_REQUEST) {
 | |
|         bh_request_msg_t *req_msg = (bh_request_msg_t *)msg->payload;
 | |
|         APP_MGR_FREE(req_msg);
 | |
|     }
 | |
| 
 | |
|     APP_MGR_FREE(msg);
 | |
| }
 | |
| 
 | |
| #endif /* BEIHAI_ENABLE_TOOL_AGENT != 0 */
 | |
| 
 | |
| /* clang-format off */
 | |
| module_interface jeff_module_interface = {
 | |
|     jeff_module_init,
 | |
|     jeff_module_install,
 | |
|     jeff_module_uninstall,
 | |
|     jeff_module_watchdog_kill,
 | |
|     jeff_module_handle_host_url,
 | |
|     jeff_module_get_module_data,
 | |
|     NULL
 | |
| };
 | |
| /* clang-format on */
 | |
| 
 | |
| #endif
 |