From a0fad9f6f46614de6d8cbf1ecbf19ee5493255f4 Mon Sep 17 00:00:00 2001 From: Sung-jae Park Date: Thu, 20 Dec 2012 17:10:16 +0900 Subject: [PATCH] Initialize the project. Change-Id: I5abec1a723b1b70877710b2c871ccd86b3669103 --- CMakeLists.txt | 75 ++ LICENSE | 83 ++ data/CMakeLists.txt | 0 include/client.h | 22 + include/conf.h | 181 ++++ include/critical_log.h | 23 + include/debug.h | 27 + include/fault.h | 23 + include/lb.h | 53 + include/main.h | 17 + include/so_handler.h | 127 +++ include/update_monitor.h | 25 + include/util.h | 29 + org.tizen.data-provider-slave.desktop | 9 + org.tizen.data-provider-slave.manifest | 19 + org.tizen.data-provider-slave.xml | 13 + packaging/org.tizen.data-provider-slave.spec | 54 + res/CMakeLists.txt | 0 src/client.c | 346 +++++++ src/conf.c | 621 ++++++++++++ src/critical_log.c | 152 +++ src/fault.c | 196 ++++ src/lb.c | 1398 ++++++++++++++++++++++++++ src/main.c | 298 ++++++ src/so_handler.c | 915 +++++++++++++++++ src/update_monitor.c | 305 ++++++ src/util.c | 174 ++++ 27 files changed, 5185 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 data/CMakeLists.txt create mode 100644 include/client.h create mode 100644 include/conf.h create mode 100644 include/critical_log.h create mode 100644 include/debug.h create mode 100644 include/fault.h create mode 100644 include/lb.h create mode 100644 include/main.h create mode 100644 include/so_handler.h create mode 100644 include/update_monitor.h create mode 100644 include/util.h create mode 100644 org.tizen.data-provider-slave.desktop create mode 100644 org.tizen.data-provider-slave.manifest create mode 100644 org.tizen.data-provider-slave.xml create mode 100644 packaging/org.tizen.data-provider-slave.spec create mode 100644 res/CMakeLists.txt create mode 100644 src/client.c create mode 100644 src/conf.c create mode 100644 src/critical_log.c create mode 100644 src/fault.c create mode 100644 src/lb.c create mode 100644 src/main.c create mode 100644 src/so_handler.c create mode 100644 src/update_monitor.c create mode 100644 src/util.c diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..8c428a4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,75 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(data-provider-slave C) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkg REQUIRED + capi-appfw-application + capi-appfw-app-manager + ail + dlog + aul + vconf + sqlite3 + db-util + glib-2.0 + gio-2.0 + bundle + ecore-x + ecore + provider + heap-monitor + livebox-service + edje + evas + livebox + elementary +) + +SET(PACKAGE "${PROJECT_NAME}") +SET(LOCALEDIR "/usr/apps/org.tizen.${PROJECT_NAME}/res/locale") + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) + +#SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") + +ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") +ADD_DEFINITIONS("-DPATH_MAX=256") +ADD_DEFINITIONS("-DPACKAGE=\"${PACKAGE}\"") +ADD_DEFINITIONS("-DLOCALEDIR=\"${LOCALEDIR}\"") +ADD_DEFINITIONS("-DEXEC_NAME=\"${PROJECT_NAME}\"") + +ADD_DEFINITIONS("-DMASTER_PKGNAME=\"org.tizen.data-provider-master\"") +ADD_DEFINITIONS("-DSLAVE_PKGNAME=\"org.tizen.data-provider-slave\"") +ADD_DEFINITIONS("-DSOCKET_FILE=\"/opt/usr/share/live_magazine/.live.socket\"") + +ADD_DEFINITIONS("-DNDEBUG") +#ADD_DEFINITIONS("-D_ENABLE_MCHECK") +ADD_DEFINITIONS("-DLOG_TAG=\"${PROJECT_NAME}\"") + +ADD_DEFINITIONS(${pkg_CFLAGS}) + +# -fpie +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Winline -Werror -g -fno-builtin-malloc") +#SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie") + +ADD_EXECUTABLE(${PROJECT_NAME} + src/main.c + src/so_handler.c + src/fault.c + src/update_monitor.c + src/conf.c + src/util.c + src/lb.c + src/client.c + src/critical_log.c +) + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkg_LDFLAGS} "-ldl") +#INSTALL(FILES ${CMAKE_SOURCE_DIR}/org.tizen.data-provider-slave.desktop DESTINATION /usr/share/applications) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/org.tizen.data-provider-slave.xml DESTINATION /usr/share/packages) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION /usr/share/license RENAME "org.tizen.${PROJECT_NAME}") +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/apps/org.tizen.${PROJECT_NAME}/bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + +# INCLUDE FOR BUILD & INSTALL .PO FILES +ADD_SUBDIRECTORY(res) +ADD_SUBDIRECTORY(data) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..27daa90 --- /dev/null +++ b/LICENSE @@ -0,0 +1,83 @@ +Flora License + +Version 1.0, May, 2012 + +http://www.tizenopensource.org/license + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +"Tizen Certified Platform" shall mean a software platform that complies with the standards set forth in the Compatibility Definition Document and passes the Compatibility Test Suite as defined from time to time by the Tizen Technical Steering Group and certified by the Tizen Association or its designated agent. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work solely as incorporated into a Tizen Certified Platform, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work solely as incorporated into a Tizen Certified Platform to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof pursuant to the copyright license above, in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; and +You must cause any modified files to carry prominent notices stating that You changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Flora License to your work + +To apply the Flora License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + + + Licensed under the Flora License, Version 1.0 (the "License"); + + you may not use this file except in compliance with the License. + + You may obtain a copy of the License at + + + + http://www.tizenopensource.org/license + + + + Unless required by applicable law or agreed to in writing, software + + distributed under the License is distributed on an "AS IS" BASIS, + + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + See the License for the specific language governing permissions and + + limitations under the License. diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/include/client.h b/include/client.h new file mode 100644 index 0000000..f5b0150 --- /dev/null +++ b/include/client.h @@ -0,0 +1,22 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern int client_init(const char *name); +extern int client_fini(void); + +/* End of a file */ + + diff --git a/include/conf.h b/include/conf.h new file mode 100644 index 0000000..ae3b7f4 --- /dev/null +++ b/include/conf.h @@ -0,0 +1,181 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +struct conf { + int width; + int height; + + int base_width; + int base_height; + double minimum_period; + + struct { + char *script; + char *abi; + char *pd_group; + double period; + } default_conf; + + struct { + char *name; + char *secured; + char *abi; + } launch_key; + + double default_packet_time; + + char *empty_content; + char *empty_title; + + char *default_content; + char *default_title; + + unsigned long minimum_space; + + char *replace_tag; + + double slave_ttl; + + int max_log_line; + int max_log_file; + + unsigned long sqlite_flush_max; + + struct { + char *conf; + char *image; + char *script; + char *root; + char *script_port; + char *slave_log; + char *db; + char *module; + } path; + + int max_size_type; + + int slave_max_load; + + double ping_time; + + char *vconf_sys_cluster; + int max_pended_ctx_events; + + int use_sw_backend; + char *provider_method; + int debug_mode; + int overwrite_content; + int com_core_thread; +}; + +extern struct conf g_conf; + +extern int conf_loader(void); + +#define BASE_W g_conf.base_width +#define BASE_H g_conf.base_height + +#define CR 13 +#define LF 10 + +#define USE_SW_BACKEND g_conf.use_sw_backend +#define PROVIDER_METHOD g_conf.provider_method +#define DEBUG_MODE g_conf.debug_mode +#define OVERWRITE_CONTENT g_conf.overwrite_content +#define COM_CORE_THREAD g_conf.com_core_thread + +#define MINIMUM_PERIOD g_conf.minimum_period + +#define DEFAULT_SCRIPT g_conf.default_conf.script +#define DEFAULT_ABI g_conf.default_conf.abi +#define DEFAULT_GROUP g_conf.default_conf.pd_group +#define NO_CHANGE g_conf.default_conf.period +#define DEFAULT_PERIOD g_conf.default_conf.period + +#define BUNDLE_SLAVE_NAME g_conf.launch_key.name +#define BUNDLE_SLAVE_SECURED g_conf.launch_key.secured +#define BUNDLE_SLAVE_ABI g_conf.launch_key.abi +#define PACKET_TIME g_conf.default_packet_time +#define CONTENT_NO_CHANGE g_conf.empty_content +#define TITLE_NO_CHANGE g_conf.empty_title +#define DEFAULT_TITLE g_conf.default_title +#define DEFAULT_CONTENT g_conf.default_content +#define MINIMUM_SPACE g_conf.minimum_space + +#define IMAGE_PATH g_conf.path.image +#define SCRIPT_PATH g_conf.path.script +#define SCRIPT_PORT_PATH g_conf.path.script_port +#define CONF_PATH g_conf.path.conf +#define ROOT_PATH g_conf.path.root +#define SLAVE_LOG_PATH g_conf.path.slave_log +#define MODULE_PATH g_conf.path.module + +#define REPLACE_TAG_APPID g_conf.replace_tag +#define SLAVE_TTL g_conf.slave_ttl + +#define MAX_LOG_LINE g_conf.max_log_line +#define MAX_LOG_FILE g_conf.max_log_file + +#define SQLITE_FLUSH_MAX g_conf.sqlite_flush_max +#define DBFILE g_conf.path.db + +#define SLAVE_MAX_LOAD g_conf.slave_max_load +#define DEFAULT_PING_TIME g_conf.ping_time + +#define MAX_ABI 256 +#define MAX_PKGNAME 512 +#define DELAY_TIME 0.0000001f +#define DEFAULT_CLUSTER "user,created" +#define MINIMUM_REACTIVATION_TIME 10 + +#define SYS_CLUSTER_KEY g_conf.vconf_sys_cluster + +#define MAX_PENDED_CTX_EVENTS g_conf.max_pended_ctx_events +#define HAPI __attribute__((visibility("hidden"))) + +/* Set language */ +#if !defined(LOCALEDIR) +#define LOCALEDIR "/usr/share/locale" +#endif + +/* Set language */ +#if !defined(PACKAGE) +#define PACKAGE "data-provider-slave" +#endif + +#define DATA_MASTER "org.tizen.data-provider-master" + +#define DEFAULT_LIFE_TIMER 20 +#define DEFAULT_LOAD_TIMER 20 +#define MINIMUM_UPDATE_INTERVAL 0.1f + +/*! + * \note + * NO_ALARM is used for disabling the alarm code + * This will turn off the alarm for checking the return of livebox functions + */ +#define NO_ALARM 1 + +/*! + * \note + * This is default action. + * This will enable the 'alarm' for checking the return time of livebox functions + */ +#define USE_ALARM 0 + +//#define DLAPI __attribute__((visibility("default"))) + +/* End of a file */ diff --git a/include/critical_log.h b/include/critical_log.h new file mode 100644 index 0000000..59c9b2e --- /dev/null +++ b/include/critical_log.h @@ -0,0 +1,23 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern int critical_log(const char *func, int line, const char *fmt, ...); +extern int critical_log_init(const char *tag); +extern int critical_log_fini(void); + +#define CRITICAL_LOG(format, args...) critical_log(__func__, __LINE__, format, args) + +/* End of a file */ diff --git a/include/debug.h b/include/debug.h new file mode 100644 index 0000000..8a659b7 --- /dev/null +++ b/include/debug.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define DbgPrint(format, arg...) LOGD("[%s/%s:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg) + +#define ErrPrint(format, arg...) LOGE("[%s/%s:%d] " format "", util_basename(__FILE__), __func__, __LINE__, ##arg) + +#define WarnPrint(format, arg...) LOGW("[%s/%s:%d] " format "", util_basename(__FILE__), __func__, __LINE__, ##arg) + +#define DbgFree(a) do { \ + free(a); \ +} while (0) + +/* End of a file */ diff --git a/include/fault.h b/include/fault.h new file mode 100644 index 0000000..e7ab9a7 --- /dev/null +++ b/include/fault.h @@ -0,0 +1,23 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern int fault_init(void); +extern int fault_fini(void); +extern int fault_mark_call(const char *pkgname, const char *filename, const char *funcname, int noalarm, int life_time); +extern int fault_unmark_call(const char *pkgname, const char *filename, const char *funcname, int noalarm); +extern void fault_disable_call_option(void); + +/* End of a file */ diff --git a/include/lb.h b/include/lb.h new file mode 100644 index 0000000..53d751a --- /dev/null +++ b/include/lb.h @@ -0,0 +1,53 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern int lb_init(void); +extern int lb_fini(void); + +extern int lb_create(const char *pkgname, const char *id, const char *content_info, int timeout, int has_livebox_script, double period, const char *cluster, const char *category, int *w, int *h, double *priority, int skip_need_to_create, const char *abi, char **out_content, char **out_title); +extern int lb_destroy(const char *pkgname, const char *id); + +extern int lb_resize(const char *pkgname, const char *id, int w, int h); +extern int lb_clicked(const char *pkgname, const char *id, const char *event, double timestamp, double x, double y); + +extern int lb_script_event(const char *pkgname, const char *id, const char *emission, const char *source, struct event_info *event_info); +extern int lb_change_group(const char *pkgname, const char *id, const char *cluster, const char *category); + +extern int lb_update(const char *pkgname, const char *id); +extern int lb_update_all(const char *pkgname, const char *cluster, const char *category); +extern void lb_pause_all(void); +extern void lb_resume_all(void); +extern int lb_set_period(const char *pkgname, const char *id, double period); +extern char *lb_pinup(const char *pkgname, const char *id, int pinup); +extern int lb_system_event(const char *pkgname, const char *id, int event); +extern int lb_system_event_all(int event); + +extern int lb_open_pd(const char *pkgname); +extern int lb_close_pd(const char *pkgname); + +extern int lb_pause(const char *pkgname, const char *id); +extern int lb_resume(const char *pkgname, const char *id); + +extern int lb_is_pinned_up(const char *pkgname, const char *id); + +extern void lb_turn_secured_on(void); + +/*! + * Exported API for each liveboxes + */ +extern const char *livebox_find_pkgname(const char *filename); + +/* End of a file */ diff --git a/include/main.h b/include/main.h new file mode 100644 index 0000000..13019db --- /dev/null +++ b/include/main.h @@ -0,0 +1,17 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* End of a file */ diff --git a/include/so_handler.h b/include/so_handler.h new file mode 100644 index 0000000..45152f7 --- /dev/null +++ b/include/so_handler.h @@ -0,0 +1,127 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +typedef int (*create_t)(const char *filename, const char *content, const char *cluster, const char *category); +typedef int (*destroy_t)(const char *filename); +typedef int (*is_updated_t)(const char *filename); +typedef int (*need_to_destroy_t)(const char *filename); +typedef int (*update_content_t)(const char *filename); +typedef int (*clicked_t)(const char *filename, const char *event, double timestamp, double x, double y); +typedef int (*script_t)(const char *filename, const char *emission, const char *source, struct event_info *event_info); +typedef int (*resize_t)(const char *filename, int type); +typedef int (*create_needed_t)(const char *cluster, const char *category); +typedef int (*change_group_t)(const char *filename, const char *cluster, const char *category); +typedef int (*get_output_info_t)(const char *filename, int *w, int *h, double *priority, char **content, char **title); +typedef int (*initialize_t)(const char *pkgname); +typedef int (*finalize_t)(void); +typedef char *(*pinup_t)(const char *filename, int pinup); +typedef int (*is_pinned_up_t)(const char *filename); +typedef int (*system_event_t)(const char *filename, int type); + +typedef int (*adaptor_create_t)(const char *pkgname, const char *filename, const char *content, const char *cluster, const char *category); +typedef int (*adaptor_destroy_t)(const char *pkgname, const char *filename); +typedef int (*adaptor_is_updated_t)(const char *pkgname, const char *filename); +typedef int (*adaptor_need_to_destroy_t)(const char *pkgname, const char *filename); +typedef int (*adaptor_update_content_t)(const char *pkgname, const char *filename); +typedef int (*adaptor_clicked_t)(const char *pkgname, const char *filename, const char *event, double timestamp, double x, double y); +typedef int (*adaptor_script_t)(const char *pkgname, const char *filename, const char *emission, const char *source, struct event_info *event_info); +typedef int (*adaptor_resize_t)(const char *pkgname, const char *filename, int type); +typedef int (*adaptor_create_needed_t)(const char *pkgname, const char *cluster, const char *category); +typedef int (*adaptor_change_group_t)(const char *pkgname, const char *filename, const char *cluster, const char *category); +typedef int (*adaptor_get_output_info_t)(const char *pkgname, const char *filename, int *w, int *h, double *priority, char **content, char **title); +typedef int (*adaptor_initialize_t)(const char *pkgname); +typedef int (*adaptor_finalize_t)(const char *pkgname); +typedef char *(*adaptor_pinup_t)(const char *pkgname, const char *filename, int pinup); +typedef int (*adaptor_is_pinned_up_t)(const char *pkgname, const char *filename); +typedef int (*adaptor_system_event_t)(const char *pkgname, const char *filename, int type); + +struct instance { + struct so_item *item; + char *id; + char *content; + char *title; + int w; + int h; + double priority; + char *cluster; + char *category; +}; + +struct so_item { + char *so_fname; + char *pkgname; + void *handle; + int timeout; + int has_livebox_script; + + Eina_List *inst_list; + + struct { + initialize_t initialize; + finalize_t finalize; + create_t create; + destroy_t destroy; + is_updated_t is_updated; + update_content_t update_content; + clicked_t clicked; + script_t script_event; + resize_t resize; + create_needed_t create_needed; + change_group_t change_group; + get_output_info_t get_output_info; + need_to_destroy_t need_to_destroy; + pinup_t pinup; + is_pinned_up_t is_pinned_up; + system_event_t sys_event; + } livebox; + + struct { + adaptor_initialize_t initialize; + adaptor_finalize_t finalize; + adaptor_create_t create; + adaptor_destroy_t destroy; + adaptor_is_updated_t is_updated; + adaptor_update_content_t update_content; + adaptor_clicked_t clicked; + adaptor_script_t script_event; + adaptor_resize_t resize; + adaptor_create_needed_t create_needed; + adaptor_change_group_t change_group; + adaptor_get_output_info_t get_output_info; + adaptor_need_to_destroy_t need_to_destroy; + adaptor_pinup_t pinup; + adaptor_is_pinned_up_t is_pinned_up; + adaptor_system_event_t sys_event; + } adaptor; +}; + +extern struct instance *so_find_instance(const char *pkgname, const char *filename); +extern int so_create(const char *pkgname, const char *filename, const char *content_info, int timeout, int has_livebox_script, const char *cluster, const char *category, const char *abi, struct instance **inst); +extern int so_is_updated(struct instance *inst); +extern int so_need_to_destroy(struct instance *inst); +extern int so_update(struct instance *inst); +extern int so_destroy(struct instance *inst); +extern int so_clicked(struct instance *inst, const char *event, double timestamp, double x, double y); +extern int so_script_event(struct instance *inst, const char *emission, const char *source, struct event_info *event_info); +extern int so_resize(struct instance *inst, int w, int h); +extern int so_create_needed(const char *pkgname, const char *cluster, const char *category, const char *abi); +extern int so_change_group(struct instance *inst, const char *cluster, const char *category); +extern int so_get_output_info(struct instance *inst, int *w, int *h, double *priority, char **content, char **title); +extern char *so_pinup(struct instance *inst, int pinup); +extern int so_is_pinned_up(struct instance *inst); +extern int so_sys_event(struct instance *inst, int event); + +/* End of a file */ diff --git a/include/update_monitor.h b/include/update_monitor.h new file mode 100644 index 0000000..5258c0e --- /dev/null +++ b/include/update_monitor.h @@ -0,0 +1,25 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern int update_monitor_init(void); +extern int update_monitor_fini(void); + +extern int update_monitor_add_update_cb(const char *filename, int (*cb)(const char *filename, void *data, int over), void *data); +extern int update_monitor_add_delete_cb(const char *filename, int (*cb)(const char *filename, void *data, int over), void *data); +extern void *update_monitor_del_update_cb(const char *filename, int (*cb)(const char *filename, void *data, int over)); +extern void *update_monitor_del_delete_cb(const char *filename, int (*cb)(const char *filename, void *data, int over)); + +// End of a file diff --git a/include/util.h b/include/util.h new file mode 100644 index 0000000..ceba60b --- /dev/null +++ b/include/util.h @@ -0,0 +1,29 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern int util_check_ext(const char *icon, const char *ext); +extern double util_timestamp(void); +extern const char *util_basename(const char *name); +extern char *util_get_current_module(char **symbol); +extern const char *util_uri_to_path(const char *uri); +extern void *util_timer_add(double interval, Eina_Bool (*cb)(void *data), void *data); +extern void util_timer_interval_set(void *timer, double interval); + +#define SCHEMA_FILE "file://" +#define SCHEMA_PIXMAP "pixmap://" +#define SCHEMA_SHM "shm://" + +/* End of a file */ diff --git a/org.tizen.data-provider-slave.desktop b/org.tizen.data-provider-slave.desktop new file mode 100644 index 0000000..42df73c --- /dev/null +++ b/org.tizen.data-provider-slave.desktop @@ -0,0 +1,9 @@ +Name=Live Data Provider - Slave +Type=Application +Exec=/usr/apps/org.tizen.data-provider-slave/bin/data-provider-slave +Icon=org.tizen.data-provider-slave.png +NoDisplay=True +Network=True +Comment=Homescreen-Live Box content data provider (slave) +X-TIZEN-TaskManage=False +X-TIZEN-Multiple=True diff --git a/org.tizen.data-provider-slave.manifest b/org.tizen.data-provider-slave.manifest new file mode 100644 index 0000000..075fcef --- /dev/null +++ b/org.tizen.data-provider-slave.manifest @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/org.tizen.data-provider-slave.xml b/org.tizen.data-provider-slave.xml new file mode 100644 index 0000000..754ba16 --- /dev/null +++ b/org.tizen.data-provider-slave.xml @@ -0,0 +1,13 @@ + + + + Sung-jae Park + Youngjoo Park + Live box data provider (native) + + + org.tizen.data-provider-slave.png + + + + diff --git a/packaging/org.tizen.data-provider-slave.spec b/packaging/org.tizen.data-provider-slave.spec new file mode 100644 index 0000000..6de4d27 --- /dev/null +++ b/packaging/org.tizen.data-provider-slave.spec @@ -0,0 +1,54 @@ +Name: org.tizen.data-provider-slave +Summary: Slave data provider +Version: 0.8.13 +Release: 1 +Group: main/app +License: Flora License +Source0: %{name}-%{version}.tar.gz +BuildRequires: cmake, gettext-tools +BuildRequires: pkgconfig(appcore-efl) +BuildRequires: pkgconfig(ail) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(aul) +BuildRequires: pkgconfig(vconf) +BuildRequires: pkgconfig(sqlite3) +BuildRequires: pkgconfig(db-util) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(bundle) +BuildRequires: pkgconfig(ecore-x) +BuildRequires: pkgconfig(provider) +BuildRequires: pkgconfig(heap-monitor) +BuildRequires: pkgconfig(livebox-service) +BuildRequires: pkgconfig(capi-appfw-application) +BuildRequires: pkgconfig(capi-appfw-app-manager) +BuildRequires: pkgconfig(ecore) +BuildRequires: pkgconfig(edje) +BuildRequires: pkgconfig(evas) +BuildRequires: pkgconfig(livebox) +BuildRequires: pkgconfig(elementary) + +%description +Loading livebox and managing their life-cycle to generate contents properly. + +%prep +%setup -q + +%build +cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} +#-fpie LDFLAGS="${LDFLAGS} -pie -O3" +CFLAGS="${CFLAGS} -Wall -Winline -Werror -fno-builtin-malloc" make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install +mkdir -p %{buildroot}/usr/share/license + +%post + +%files -n org.tizen.data-provider-slave +%manifest org.tizen.data-provider-slave.manifest +%defattr(-,root,root,-) +/usr/apps/org.tizen.data-provider-slave/bin/data-provider-slave +/usr/share/packages/org.tizen.data-provider-slave.xml +/usr/share/license/* diff --git a/res/CMakeLists.txt b/res/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/client.c b/src/client.c new file mode 100644 index 0000000..b1751d7 --- /dev/null +++ b/src/client.c @@ -0,0 +1,346 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "critical_log.h" +#include "conf.h" +#include "debug.h" +#include "client.h" +#include "so_handler.h" +#include "lb.h" +#include "util.h" + +static struct info { + Ecore_Timer *ping_timer; +} s_info = { + .ping_timer = NULL, +}; + +static int method_new(struct event_arg *arg, int *width, int *height, double *priority, void *data) +{ + int ret; + DbgPrint("Create: pkgname[%s], id[%s], content[%s], timeout[%d], has_script[%d], period[%lf], cluster[%s], category[%s], skip[%d], abi[%s]\n", + arg->pkgname, + arg->id, + arg->info.lb_create.content, + arg->info.lb_create.timeout, + arg->info.lb_create.has_script, + arg->info.lb_create.period, + arg->info.lb_create.cluster, arg->info.lb_create.category, + arg->info.lb_create.skip_need_to_create, + arg->info.lb_create.abi); + + ret = lb_create(arg->pkgname, arg->id, + arg->info.lb_create.content, + arg->info.lb_create.timeout, + arg->info.lb_create.has_script, + arg->info.lb_create.period, + arg->info.lb_create.cluster, + arg->info.lb_create.category, + width, height, priority, + arg->info.lb_create.skip_need_to_create, + arg->info.lb_create.abi, + &arg->info.lb_create.out_content, + &arg->info.lb_create.out_title); + + if (ret == 0) { + if (arg->info.lb_create.width > 0 && arg->info.lb_create.height > 0) { + if (*width != arg->info.lb_create.width || *height != arg->info.lb_create.height) { + int tmp; + tmp = lb_resize(arg->pkgname, arg->id, arg->info.lb_create.width, arg->info.lb_create.height); + DbgPrint("Resize[%dx%d] returns: %d\n", arg->info.lb_create.width, arg->info.lb_create.height, tmp); + } + } + + arg->info.lb_create.out_is_pinned_up = (lb_is_pinned_up(arg->pkgname, arg->id) == 1); + } + + return ret; +} + +static int method_renew(struct event_arg *arg, void *data) +{ + int ret; + int w; + int h; + double priority; + + DbgPrint("Re-create: pkgname[%s], id[%s], content[%s], timeout[%d], has_script[%d], period[%lf], cluster[%s], category[%s], abi[%s]\n", + arg->pkgname, arg->id, + arg->info.lb_recreate.content, + arg->info.lb_recreate.timeout, + arg->info.lb_recreate.has_script, + arg->info.lb_recreate.period, + arg->info.lb_recreate.cluster, + arg->info.lb_recreate.category, + arg->info.lb_recreate.abi); + + ret = lb_create(arg->pkgname, arg->id, + arg->info.lb_recreate.content, + arg->info.lb_recreate.timeout, + arg->info.lb_recreate.has_script, + arg->info.lb_recreate.period, + arg->info.lb_recreate.cluster, + arg->info.lb_recreate.category, + &w, &h, &priority, + 1, + arg->info.lb_recreate.abi, + &arg->info.lb_recreate.out_content, + &arg->info.lb_recreate.out_title); + if (ret == 0) { + if (w != arg->info.lb_recreate.width || h != arg->info.lb_recreate.height) { + int tmp; + tmp = lb_resize(arg->pkgname, arg->id, arg->info.lb_recreate.width, arg->info.lb_recreate.height); + DbgPrint("Resize[%dx%d] returns: %d\n", arg->info.lb_recreate.width, arg->info.lb_recreate.height, tmp); + } else { + DbgPrint("No need to change the size: %dx%d\n", w, h); + } + + arg->info.lb_recreate.out_is_pinned_up = (lb_is_pinned_up(arg->pkgname, arg->id) == 1); + } + + return ret; +} + +static int method_delete(struct event_arg *arg, void *data) +{ + int ret; + DbgPrint("pkgname[%s] id[%s]\n", arg->pkgname, arg->id); + ret = lb_destroy(arg->pkgname, arg->id); + return ret; +} + +static int method_content_event(struct event_arg *arg, void *data) +{ + int ret; + struct event_info info; + + info = arg->info.content_event.info; + + ret = lb_script_event(arg->pkgname, arg->id, + arg->info.content_event.emission, arg->info.content_event.source, + &info); + return ret; +} + +static int method_clicked(struct event_arg *arg, void *data) +{ + int ret; + + DbgPrint("pkgname[%s] id[%s] event[%s] timestamp[%lf] x[%lf] y[%lf]\n", + arg->pkgname, arg->id, + arg->info.clicked.event, arg->info.clicked.timestamp, + arg->info.clicked.x, arg->info.clicked.y); + ret = lb_clicked(arg->pkgname, arg->id, + arg->info.clicked.event, + arg->info.clicked.timestamp, arg->info.clicked.x, arg->info.clicked.y); + + return ret; +} + +static int method_text_signal(struct event_arg *arg, void *data) +{ + int ret; + struct event_info info; + + info = arg->info.text_signal.info; + + DbgPrint("pkgname[%s] id[%s] emission[%s] source[%s]\n", arg->pkgname, arg->id, arg->info.text_signal.emission, arg->info.text_signal.source); + ret = lb_script_event(arg->pkgname, arg->id, + arg->info.text_signal.emission, arg->info.text_signal.source, + &info); + + return ret; +} + +static int method_resize(struct event_arg *arg, void *data) +{ + int ret; + + DbgPrint("pkgname[%s] id[%s] w[%d] h[%d]\n", arg->pkgname, arg->id, arg->info.resize.w, arg->info.resize.h); + ret = lb_resize(arg->pkgname, arg->id, arg->info.resize.w, arg->info.resize.h); + + return ret; +} + +static int method_set_period(struct event_arg *arg, void *data) +{ + int ret; + DbgPrint("pkgname[%s] id[%s] period[%lf]\n", arg->pkgname, arg->id, arg->info.set_period.period); + ret = lb_set_period(arg->pkgname, arg->id, arg->info.set_period.period); + return ret; +} + +static int method_change_group(struct event_arg *arg, void *data) +{ + int ret; + DbgPrint("pkgname[%s] id[%s] cluster[%s] category[%s]\n", arg->pkgname, arg->id, arg->info.change_group.cluster, arg->info.change_group.category); + ret = lb_change_group(arg->pkgname, arg->id, arg->info.change_group.cluster, arg->info.change_group.category); + return ret; +} + +static int method_pinup(struct event_arg *arg, void *data) +{ + DbgPrint("pkgname[%s] id[%s] state[%d]\n", arg->pkgname, arg->id, arg->info.pinup.state); + arg->info.pinup.content_info = lb_pinup(arg->pkgname, arg->id, arg->info.pinup.state); + return arg->info.pinup.content_info ? 0 : -ENOTSUP; +} + +static int method_update_content(struct event_arg *arg, void *data) +{ + int ret; + + if (!arg->id || !strlen(arg->id)) { + DbgPrint("pkgname[%s] cluster[%s] category[%s]\n", arg->pkgname, arg->info.update_content.cluster, arg->info.update_content.category); + ret = lb_update_all(arg->pkgname, arg->info.update_content.cluster, arg->info.update_content.category); + } else { + DbgPrint("Update [%s]\n", arg->id); + ret = lb_update(arg->pkgname, arg->id); + } + + return ret; +} + +static int method_pause(struct event_arg *arg, void *data) +{ + lb_pause_all(); + if (s_info.ping_timer) + ecore_timer_freeze(s_info.ping_timer); + + sqlite3_release_memory(SQLITE_FLUSH_MAX); + malloc_trim(0); + return 0; +} + +static int method_resume(struct event_arg *arg, void *data) +{ + lb_resume_all(); + if (s_info.ping_timer) + ecore_timer_thaw(s_info.ping_timer); + return 0; +} + +static Eina_Bool send_ping_cb(void *data) +{ + provider_send_ping(); + return ECORE_CALLBACK_RENEW; +} + +static int method_disconnected(struct event_arg *arg, void *data) +{ + if (s_info.ping_timer) { + ecore_timer_del(s_info.ping_timer); + s_info.ping_timer = NULL; + } + + elm_exit(); + return 0; +} + +static int method_connected(struct event_arg *arg, void *data) +{ + int ret; + ret = provider_send_hello(); + if (ret == 0) { + s_info.ping_timer = ecore_timer_add(DEFAULT_PING_TIME, send_ping_cb, NULL); + if (!s_info.ping_timer) + ErrPrint("Failed to add a ping timer\n"); + } + + return 0; +} + +static int method_pd_created(struct event_arg *arg, void *data) +{ + int ret; + + ret = lb_open_pd(arg->pkgname); + DbgPrint("%s Open PD: %d\n", arg->pkgname, ret); + + return 0; +} + +static int method_pd_destroyed(struct event_arg *arg, void *data) +{ + int ret; + + ret = lb_close_pd(arg->pkgname); + DbgPrint("%s Close PD: %d\n", arg->pkgname, ret); + + return 0; +} + +static int method_lb_pause(struct event_arg *arg, void *data) +{ + return lb_pause(arg->pkgname, arg->id); +} + +static int method_lb_resume(struct event_arg *arg, void *data) +{ + return lb_resume(arg->pkgname, arg->id); +} + +HAPI int client_init(const char *name) +{ + struct event_handler table = { + .lb_create = method_new, + .lb_recreate = method_renew, + .lb_destroy = method_delete, + .content_event = method_content_event, + .clicked = method_clicked, + .text_signal = method_text_signal, + .resize = method_resize, + .set_period = method_set_period, + .change_group = method_change_group, + .pinup = method_pinup, + .update_content = method_update_content, + .pause = method_pause, + .resume = method_resume, + .disconnected = method_disconnected, + .connected = method_connected, + .pd_create = method_pd_created, + .pd_destroy = method_pd_destroyed, + .lb_pause = method_lb_pause, + .lb_resume = method_lb_resume, + }; + + provider_init(ecore_x_display_get(), name, &table, NULL); + return 0; +} + +HAPI int client_fini(void) +{ + provider_fini(); + return 0; +} + +/* End of a file */ + diff --git a/src/conf.c b/src/conf.c new file mode 100644 index 0000000..1a1fccd --- /dev/null +++ b/src/conf.c @@ -0,0 +1,621 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include + +#include "conf.h" +#include "util.h" +#include "debug.h" + +HAPI struct conf g_conf = { + .width = 0, + .height = 0, + + .base_width = 720, + .base_height = 1280, + + .minimum_period = 1.0f, + + .default_conf.script = "edje", + .default_conf.abi = "c", + .default_conf.pd_group = "disclosure", + .default_conf.period = -1.0f, + + .launch_key.name = "name", + .launch_key.secured = "secured", + .launch_key.abi = "abi", + + .default_packet_time = 0.0001f, + + .empty_content = "", + .empty_title = "", + + .default_content = "default", + .default_title = "", + + .minimum_space = 5242880, + + .replace_tag = "/APPID/", + + .slave_ttl = 30.0f, + + .max_log_line = 1000, + .max_log_file = 3, + + .sqlite_flush_max = 1048576, + + .path = { + .image = "/opt/usr/share/live_magazine/", + .slave_log = "/opt/usr/share/live_magazine/log", + .root = "/opt/usr/live/", + .script_port = "/opt/usr/live/script_port/", + .db = "/opt/dbspace/.livebox.db", + + /*! + * This is not loaded from the conf file + */ + .conf = "/opt/usr/live/%s/etc/%s.conf", + .script = "/opt/usr/live/%s/res/script/%s.edj", + .module = "/opt/usr/live/%s/libexec/liblive-%s.so", + }, + + .ping_time = 240.0f, + .slave_max_load = 30, + .vconf_sys_cluster = "file/private/org.tizen.data-provider-master/cluster", + .max_pended_ctx_events = 256, + + .use_sw_backend = 0, + .provider_method = "pixmap", + .debug_mode = 0, + .overwrite_content = 0, + .com_core_thread = 1, +}; + +static void conf_update_size(void) +{ + ecore_x_window_size_get(0, &g_conf.width, &g_conf.height); +} + +static void use_sw_backend_handler(char *buffer) +{ + g_conf.use_sw_backend = !strcasecmp(buffer, "true"); + DbgPrint("SW Backend: %d\n", g_conf.use_sw_backend); +} + +static void provider_method_handler(char *buffer) +{ + g_conf.provider_method = strdup(buffer); + if (!g_conf.provider_method) + ErrPrint("Heap: %s\n", strerror(errno)); + + DbgPrint("Method: %s\n", g_conf.provider_method); +} + +static void debug_mode_handler(char *buffer) +{ + g_conf.debug_mode = !strcasecmp(buffer, "true"); + DbgPrint("Debug mode: %d\n", g_conf.debug_mode); +} + +static void overwrite_content_handler(char *buffer) +{ + g_conf.overwrite_content = !strcasecmp(buffer, "true"); + DbgPrint("Overwrite Content: %d\n", g_conf.overwrite_content); +} + +static void com_core_thread_handler(char *buffer) +{ + g_conf.com_core_thread = !strcasecmp(buffer, "true"); + DbgPrint("Com core thread: %d\n", g_conf.com_core_thread); +} + +static void base_width_handler(char *buffer) +{ + if (sscanf(buffer, "%d", &g_conf.base_width) != 1) + ErrPrint("Failed to parse the base_width\n"); + + DbgPrint("Base width: %d\n", g_conf.base_width); +} + +static void base_height_handler(char *buffer) +{ + if (sscanf(buffer, "%d", &g_conf.base_height) != 1) + ErrPrint("Failed to parse the base_height\n"); + DbgPrint("Base height: %d\n", g_conf.base_height); +} + +static void minimum_period_handler(char *buffer) +{ + if (sscanf(buffer, "%lf", &g_conf.minimum_period) != 1) + ErrPrint("Failed to parse the minimum_period\n"); + DbgPrint("Minimum period: %lf\n", g_conf.minimum_period); +} + +static void script_handler(char *buffer) +{ + g_conf.default_conf.script = strdup(buffer); + if (!g_conf.default_conf.script) + ErrPrint("Heap: %s\n", strerror(errno)); + DbgPrint("Default script: %s\n", g_conf.default_conf.script); +} + +static void default_abi_handler(char *buffer) +{ + g_conf.default_conf.abi = strdup(buffer); + if (!g_conf.default_conf.abi) + ErrPrint("Heap: %s\n", strerror(errno)); + DbgPrint("Default ABI: %s\n", g_conf.default_conf.abi); +} + +static void default_group_handler(char *buffer) +{ + g_conf.default_conf.pd_group = strdup(buffer); + if (!g_conf.default_conf.pd_group) + ErrPrint("Heap: %s\n", strerror(errno)); + DbgPrint("Default PD Group: %s\n", g_conf.default_conf.pd_group); +} + +static void default_period_handler(char *buffer) +{ + if (sscanf(buffer, "%lf", &g_conf.default_conf.period) != 1) + ErrPrint("Failed to parse the default_period\n"); + DbgPrint("Default Period: %lf\n", g_conf.default_conf.period); +} + +static void default_packet_time_handler(char *buffer) +{ + if (sscanf(buffer, "%lf", &g_conf.default_packet_time) != 1) + ErrPrint("Failed to parse the default_packet_time\n"); + DbgPrint("Default packet time: %lf\n", g_conf.default_packet_time); +} + +static void default_content_handler(char *buffer) +{ + g_conf.default_content = strdup(buffer); + if (!g_conf.default_content) + ErrPrint("Heap: %s\n", strerror(errno)); + DbgPrint("Default content: %s\n", g_conf.default_content); +} + +static void default_title_handler(char *buffer) +{ + g_conf.default_title = strdup(buffer); + if (!g_conf.default_title) + ErrPrint("Heap: %s\n", strerror(errno)); + DbgPrint("Default title: %s\n", g_conf.default_title); +} + +static void minimum_space_handler(char *buffer) +{ + if (sscanf(buffer, "%lu", &g_conf.minimum_space) != 1) + ErrPrint("Failed to parse the minimum_space\n"); + DbgPrint("Minimum space: %lu\n", g_conf.minimum_space); +} + +static void replace_tag_handler(char *buffer) +{ + g_conf.replace_tag = strdup(buffer); + if (!g_conf.replace_tag) + ErrPrint("Heap: %s\n", strerror(errno)); + DbgPrint("Replace Tag: %s\n", g_conf.replace_tag); +} + +static void slave_ttl_handler(char *buffer) +{ + if (sscanf(buffer, "%lf", &g_conf.slave_ttl) != 1) + ErrPrint("Failed to parse the slave_ttl\n"); + DbgPrint("Slave TTL: %s\n", g_conf.slave_ttl); +} + +static void max_log_line_handler(char *buffer) +{ + if (sscanf(buffer, "%d", &g_conf.max_log_line) != 1) + ErrPrint("Failed to parse the max_log_line\n"); + DbgPrint("Max log line: %d\n", g_conf.max_log_line); +} + +static void max_log_file_handler(char *buffer) +{ + if (sscanf(buffer, "%d", &g_conf.max_log_file) != 1) + ErrPrint("Failed to parse the max_log_file\n"); + DbgPrint("Max log file: %d\n", g_conf.max_log_file); +} + +static void sqlite_flush_max_handler(char *buffer) +{ + if (sscanf(buffer, "%lu", &g_conf.sqlite_flush_max) != 1) + ErrPrint("Failed to parse the sqlite_flush_max\n"); + DbgPrint("Flush size: %lu\n", g_conf.sqlite_flush_max); +} + +static void db_path_handler(char *buffer) +{ + g_conf.path.db = strdup(buffer); + if (!g_conf.path.db) + ErrPrint("Heap: %s\n", strerror(errno)); + DbgPrint("DB Path: %s\n", g_conf.path.db); +} + +static void log_path_handler(char *buffer) +{ + g_conf.path.slave_log = strdup(buffer); + if (!g_conf.path.slave_log) + ErrPrint("Heap: %s\n", strerror(errno)); + DbgPrint("LOG Path: %s\n", g_conf.path.slave_log); +} + +static void script_port_path_handler(char *buffer) +{ + g_conf.path.script_port = strdup(buffer); + if (!g_conf.path.script_port) + ErrPrint("Heap: %s\n", strerror(errno)); + DbgPrint("Script Port PATH: %s\n", g_conf.path.script_port); +} + +static void share_path_handler(char *buffer) +{ + g_conf.path.image = strdup(buffer); + if (!g_conf.path.image) + ErrPrint("Heap: %s\n", strerror(errno)); + DbgPrint("Shared folder: %s\n", g_conf.path.image); +} + +static void ping_time_handler(char *buffer) +{ + if (sscanf(buffer, "%lf", &g_conf.ping_time) != 1) + ErrPrint("Failed to parse the ping_time\n"); + g_conf.ping_time /= 2.0f; /*!< Half */ + DbgPrint("Default ping time: %lf\n", g_conf.ping_time); +} + +static void slave_max_loader(char *buffer) +{ + if (sscanf(buffer, "%d", &g_conf.slave_max_load) != 1) + ErrPrint("Failed to parse the slave_max_load\n"); + DbgPrint("Max load: %d\n", g_conf.slave_max_load); +} + +static void vconf_sys_cluster_handler(char *buffer) +{ + g_conf.vconf_sys_cluster = strdup(buffer); + if (!g_conf.vconf_sys_cluster) + ErrPrint("Heap %s\n", strerror(errno)); + DbgPrint("System cluster vconf key: %s\n", g_conf.vconf_sys_cluster); +} + +static void max_pended_ctx_event_handler(char *buffer) +{ + if (sscanf(buffer, "%d", &g_conf.max_pended_ctx_events) != 1) + ErrPrint("Failed to parse the max_pended_ctx_events\n"); + DbgPrint("Maximum pended event: %d\n", g_conf.max_pended_ctx_events); +} + +HAPI int conf_loader(void) +{ + FILE *fp; + int c; + enum state { + START, + SPACE, + TOKEN, + VALUE, + ERROR, + COMMENT, + END, + } state; + int ch_idx; + int token_idx; + int buffer_idx; + int quote; + int linelen; + char buffer[256]; + static const struct token_parser { + const char *name; + void (*handler)(char *buffer); + } token_handler[] = { + { + .name = "base_width", + .handler = base_width_handler, + }, + { + .name = "base_height", + .handler = base_height_handler, + }, + { + .name = "minimum_period", + .handler = minimum_period_handler, + }, + { + .name = "script", + .handler = script_handler, + }, + { + .name = "default_abi", + .handler = default_abi_handler, + }, + { + .name = "default_group", + .handler = default_group_handler, + }, + { + .name = "default_period", + .handler = default_period_handler, + }, + { + .name = "default_packet_time", + .handler = default_packet_time_handler, + }, + { + .name = "default_content", + .handler = default_content_handler, + }, + { + .name = "default_title", + .handler = default_title_handler, + }, + { + .name = "minimum_space", + .handler = minimum_space_handler, + }, + { + .name = "replace_tag", + .handler = replace_tag_handler, + }, + { + .name = "slave_ttl", + .handler = slave_ttl_handler, + }, + { + .name = "max_log_line", + .handler = max_log_line_handler, + }, + { + .name = "max_log_file", + .handler = max_log_file_handler, + }, + { + .name = "sqilte_flush_max", + .handler = sqlite_flush_max_handler, + }, + { + .name = "db_path", + .handler = db_path_handler, + }, + { + .name = "log_path", + .handler = log_path_handler, + }, + { + .name = "share_path", + .handler = share_path_handler, + }, + { + .name = "script_port_path", + .handler = script_port_path_handler, + }, + { + .name = "ping_interval", + .handler = ping_time_handler, + }, + { + .name = "slave_max_load", + .handler = slave_max_loader, + }, + { + .name = "vconf_sys_cluster", + .handler = vconf_sys_cluster_handler, + }, + { + .name = "max_pended_ctx_event", + .handler = max_pended_ctx_event_handler, + }, + { + .name = "use_sw_backend", + .handler = use_sw_backend_handler, + }, + { + .name = "provider_method", + .handler = provider_method_handler, + }, + { + .name = "debug_mode", + .handler = debug_mode_handler, + }, + { + .name = "overwrite_content", + .handler = overwrite_content_handler, + }, + { + .name = "com_core_thread", + .handler = com_core_thread_handler, + }, + { + .name = NULL, + .handler = NULL, + }, + }; + + conf_update_size(); + + fp = fopen("/usr/share/data-provider-master/conf.ini", "rt"); + if (!fp) { + ErrPrint("Error: %s\n", strerror(errno)); + return -EIO; + } + + state = START; + ch_idx = 0; + token_idx = -1; + buffer_idx = 0; + quote = 0; + linelen = 0; + do { + c = getc(fp); + if ((c == EOF) && (state == VALUE)) { + LOGD("[%s:%d] VALUE state EOF\n", __func__, __LINE__); + state = END; + } + + switch (state) { + case COMMENT: + if (c == CR || c == LF || c == EOF) { + buffer[buffer_idx] = '\0'; + + state = START; + token_idx = -1; + ch_idx = 0; + buffer_idx = 0; + linelen = -1; /* Will be ZERO by follwing increment code */ + quote = 0; + } else { + buffer[buffer_idx++] = c; + if (buffer_idx == (sizeof(buffer) - 1)) { + buffer[buffer_idx] = '\0'; + buffer_idx = 0; + } + } + break; + case START: + if (linelen == 0 && c == '#') { + state = COMMENT; + } else if (isspace(c)) { + /* Ignore empty space */ + } else { + state = TOKEN; + ungetc(c, fp); + } + break; + case SPACE: + if (c == '=') + state = VALUE; + else if (!isspace(c)) + state = ERROR; + break; + case VALUE: + if (c == '"') { + if (quote == 1) { + buffer[buffer_idx] = '\0'; + state = END; + } else if (buffer_idx != 0) { + buffer[buffer_idx++] = c; + if (buffer_idx >= sizeof(buffer)) + state = ERROR; + } else { + quote = 1; + } + } else if (isspace(c)) { + if (buffer_idx == 0) { + /* Ignore */ + } else if (quote == 1) { + buffer[buffer_idx++] = c; + if (buffer_idx >= sizeof(buffer)) + state = ERROR; + } else { + buffer[buffer_idx] = '\0'; + ungetc(c, fp); + state = END; + } + } else { + buffer[buffer_idx++] = c; + if (buffer_idx >= sizeof(buffer)) + state = ERROR; + } + break; + case TOKEN: + if (c == '=') { + if (token_idx < 0) + state = ERROR; + else + state = VALUE; + } else if (isspace(c)) { + if (token_idx < 0) + break; + + if (token_handler[token_idx].name[ch_idx] != '\0') + state = ERROR; + else + state = SPACE; + } else { + if (token_idx < 0) { + /* Now start to find a token! */ + token_idx = 0; + } + + if (token_handler[token_idx].name[ch_idx] == c) { + ch_idx++; + } else { + ungetc(c, fp); + while (ch_idx-- > 0) + ungetc(token_handler[token_idx].name[ch_idx], fp); + + token_idx++; + + if (token_handler[token_idx].name == NULL) + state = ERROR; + else + ch_idx = 0; + } + } + break; + case ERROR: + if (c == CR || c == LF || c == EOF) { + state = START; + token_idx = -1; + buffer_idx = 0; + ch_idx = 0; + linelen = -1; + quote = 0; + } + break; + case END: + if (c == LF || c == CR || c == EOF) { + state = START; + + if (token_idx >= 0 && token_handler[token_idx].handler) { + buffer[buffer_idx] = '\0'; + DbgPrint("BUFFER: [%s]\n", buffer); + token_handler[token_idx].handler(buffer); + } + + token_idx = -1; + ch_idx = 0; + buffer_idx = 0; + linelen = -1; + quote = 0; + /* Finish */ + } else if (isspace(c)) { + /* ignore */ + } else { + state = ERROR; + } + break; + default: + /* ?? */ + break; + } + + linelen++; + } while (c != EOF); + + fclose(fp); + return 0; +} + +/* End of a file */ diff --git a/src/critical_log.c b/src/critical_log.c new file mode 100644 index 0000000..b63395b --- /dev/null +++ b/src/critical_log.c @@ -0,0 +1,152 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "util.h" +#include "conf.h" +#include "critical_log.h" +#include "debug.h" + +static struct { + FILE *fp; + int file_id; + int nr_of_lines; + char *filename; +} s_info = { + .fp = NULL, + .file_id = 0, + .nr_of_lines = 0, + .filename = NULL, +}; + + + +HAPI int critical_log(const char *func, int line, const char *fmt, ...) +{ + va_list ap; + int ret; + struct timeval tv; + + if (!s_info.fp) + return -EIO; + + gettimeofday(&tv, NULL); + fprintf(s_info.fp, "%d %lu.%lu [%s:%d] ", getpid(), tv.tv_sec, tv.tv_usec, util_basename((char *)func), line); + + va_start(ap, fmt); + ret = vfprintf(s_info.fp, fmt, ap); + va_end(ap); + + s_info.nr_of_lines++; + if (s_info.nr_of_lines == MAX_LOG_LINE) { + char *filename; + int namelen; + + s_info.file_id = (s_info.file_id + 1) % MAX_LOG_FILE; + + namelen = strlen(s_info.filename) + strlen(SLAVE_LOG_PATH) + 20; + filename = malloc(namelen); + if (filename) { + snprintf(filename, namelen, "%s/%d_%s", SLAVE_LOG_PATH, s_info.file_id, s_info.filename); + + if (s_info.fp) + fclose(s_info.fp); + + s_info.fp = fopen(filename, "w+"); + if (!s_info.fp) + ErrPrint("Failed to open a file: %s\n", filename); + + free(filename); + } + + s_info.nr_of_lines = 0; + } + return ret; +} + + + +HAPI int critical_log_init(const char *name) +{ + int namelen; + char *filename; + + if (s_info.fp) + return 0; + + s_info.filename = strdup(name); + if (!s_info.filename) { + ErrPrint("Failed to create a log file\n"); + return -ENOMEM; + } + + namelen = strlen(name) + strlen(SLAVE_LOG_PATH) + 20; + + filename = malloc(namelen); + if (!filename) { + ErrPrint("Failed to create a log file\n"); + free(s_info.filename); + s_info.filename = NULL; + return -ENOMEM; + } + + snprintf(filename, namelen, "%s/%d_%s", SLAVE_LOG_PATH, s_info.file_id, name); + + s_info.fp = fopen(filename, "w+"); + if (!s_info.fp) { + ErrPrint("Failed to open log: %s\n", strerror(errno)); + free(s_info.filename); + s_info.filename = NULL; + free(filename); + return -EIO; + } + + free(filename); + return 0; +} + + + +HAPI int critical_log_fini(void) +{ + if (s_info.filename) { + free(s_info.filename); + s_info.filename = NULL; + } + + if (s_info.fp) { + fclose(s_info.fp); + s_info.fp = NULL; + } + + return 0; +} + + + +/* End of a file */ diff --git a/src/fault.c b/src/fault.c new file mode 100644 index 0000000..9383701 --- /dev/null +++ b/src/fault.c @@ -0,0 +1,196 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "critical_log.h" +#include "main.h" +#include "debug.h" +#include "fault.h" +#include "conf.h" +#include "client.h" +#include "util.h" + +static struct info { + struct timeval alarm_tv; + int marked; + int disable_checker; +} s_info = { + .marked = 0, + .disable_checker = 0, +}; + +static void signal_handler(int signum, siginfo_t *info, void *unused) +{ + char *so_fname; + char *symbol = NULL; + + so_fname = util_get_current_module(&symbol); + + if (info->si_signo == SIGALRM) { + struct timeval tv; + struct timeval res_tv; + + if (!s_info.marked) { + DbgPrint("Ignore false alarm signal [false]\n"); + return; + } + + gettimeofday(&tv, NULL); + + timersub(&tv, &s_info.alarm_tv, &res_tv); + + /*! + * \note + * GAP: 1 sec + */ + if (res_tv.tv_sec < DEFAULT_LIFE_TIMER) { + DbgPrint("Ignore false alarm signal [%d]\n", res_tv.tv_sec); + return; + } + + DbgPrint("ALARM: %d.%d (%d, %d)\n", + res_tv.tv_sec, res_tv.tv_usec, DEFAULT_LIFE_TIMER, DEFAULT_LOAD_TIMER); + } else if (so_fname) { + int fd; + char log_fname[256]; + + snprintf(log_fname, sizeof(log_fname), "%s/slave.%d", SLAVE_LOG_PATH, getpid()); + fd = open(log_fname, O_WRONLY|O_CREAT|O_SYNC, 0644); + if (fd >= 0) { + if (write(fd, so_fname, strlen(so_fname)) != strlen(so_fname)) + ErrPrint("Failed to recording the fault SO filename (%s)\n", so_fname); + close(fd); + } + } + + ErrPrint("=====\n"); + ErrPrint("SIGNAL> Received from PID[%d]\n", info->si_pid); + ErrPrint("SIGNAL> Signal: %d (%d)\n", signum, info->si_signo); + ErrPrint("SIGNAL> Error code: %d\n", info->si_code); + ErrPrint("SIGNAL> Address: %p\n", info->si_addr); + ErrPrint("Package: [%s] Symbol[%s]\n", so_fname, symbol); + free(so_fname); + free(symbol); + + _exit(0); + return; +} + +HAPI int fault_init(void) +{ + struct sigaction act; + + if (access("/tmp/live.err", F_OK) == 0) + ErrPrint("Error log still exists (/tmp/live.err)\n"); + + act.sa_sigaction = signal_handler; + act.sa_flags = SA_SIGINFO; + + sigemptyset(&act.sa_mask); + sigaddset(&act.sa_mask, SIGSEGV); + sigaddset(&act.sa_mask, SIGABRT); + sigaddset(&act.sa_mask, SIGILL); + sigaddset(&act.sa_mask, SIGUSR1); + sigaddset(&act.sa_mask, SIGALRM); + + if (sigaction(SIGSEGV, &act, NULL) < 0) + ErrPrint("Failed to install the SEGV handler\n"); + + if (sigaction(SIGABRT, &act, NULL) < 0) + ErrPrint("Faield to install the ABRT handler\n"); + + if (sigaction(SIGILL, &act, NULL) < 0) + ErrPrint("Faield to install the ILL handler\n"); + + if (sigaction(SIGUSR1, &act, NULL) < 0) + ErrPrint("Failed to install the USR1 handler\n"); + + if (sigaction(SIGALRM, &act, NULL) < 0) + ErrPrint("Failed to install the ALRM handler\n"); + + return 0; +} + +HAPI int fault_fini(void) +{ + /*! + * \todo + * remove all signal handlers + */ + return 0; +} + +HAPI int fault_mark_call(const char *pkgname, const char *filename, const char *funcname, int noalarm, int life_time) +{ + if (!s_info.disable_checker) + provider_send_call(pkgname, filename, funcname); + /*! + * \NOTE + * To use this "alarm", the livebox have to do not use the 'sleep' series functions. + * because those functions will generate alarm signal. + * then the module will be deactivated + * + * Enable alarm for detecting infinite loop + */ + if (!noalarm) { + gettimeofday(&s_info.alarm_tv, NULL); + s_info.marked = 1; + alarm(life_time); + } + + return 0; +} + +HAPI int fault_unmark_call(const char *pkgname, const char *filename, const char *funcname, int noalarm) +{ + if (!noalarm) { + /*! + * \NOTE + * Disable alarm + */ + alarm(0); + s_info.marked = 0; + } + + if (!s_info.disable_checker) + provider_send_ret(pkgname, filename, funcname); + return 0; +} + +HAPI void fault_disable_call_option(void) +{ + s_info.disable_checker = 1; +} + +/* End of a file */ diff --git a/src/lb.c b/src/lb.c new file mode 100644 index 0000000..56bc478 --- /dev/null +++ b/src/lb.c @@ -0,0 +1,1398 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include /* exit */ +#include + +#include +#include + +#include +#include +#include + +#include "critical_log.h" +#include "debug.h" +#include "conf.h" +#include "so_handler.h" +#include "lb.h" +#include "update_monitor.h" +#include "fault.h" +#include "util.h" + +int errno; + +struct item { + Ecore_Timer *timer; + struct instance *inst; + int monitor_cnt; + Ecore_Timer *monitor; + int deleteme; + double update_interval; + int heavy_updating; /* Only for debugging message */ + int is_paused; /* 1 is paused, 0 is resumed */ + double sleep_at; +}; + +static struct info { + Eina_List *item_list; + struct item *update; + Eina_List *pending_list; + Ecore_Timer *pending_timer; + Eina_List *pd_open_pending_list; + Ecore_Timer *pd_open_pending_timer; + int paused; + Eina_List *pd_list; + int secured; + int pending_timer_freezed; +} s_info = { + .item_list = NULL, + .update = NULL, + .pending_list = NULL, + .pending_timer = NULL, + .pd_open_pending_list = NULL, + .pd_open_pending_timer = NULL, + .paused = 0, + .pd_list = NULL, + .secured = 0, + .pending_timer_freezed = 0, +}; + +static Eina_Bool updator_cb(void *data); + +static void pending_timer_freeze(void) +{ + DbgPrint("Freezed Count: %d\n", s_info.pending_timer_freezed); + if (s_info.pending_timer && !s_info.pending_timer_freezed) { + DbgPrint("Freeze the pending timer\n"); + ecore_timer_freeze(s_info.pending_timer); + } + + s_info.pending_timer_freezed++; +} + +static void pending_timer_thaw(void) +{ + DbgPrint("Freezed Count: %d\n", s_info.pending_timer_freezed); + if (!s_info.pending_timer_freezed) + return; + + s_info.pending_timer_freezed--; + if (s_info.pending_timer && !s_info.pending_timer_freezed) { + DbgPrint("Thaw the pending timer\n"); + ecore_timer_thaw(s_info.pending_timer); + } +} + +/* + * -1 : PD is opened, but not mine + * 0 : PD is not opened + * 1 : my PD is opened + */ +static inline int pd_is_opened(const char *pkgname) +{ + int i; + Eina_List *l; + char *tmp; + + i = 0; + EINA_LIST_FOREACH(s_info.pd_list, l, tmp) { + if (pkgname && !strcmp(pkgname, tmp)) + return 1; + + i++; + } + + return i > 0 ? -1 : 0; +} + +static Eina_Bool pd_open_pended_cmd_consumer_cb(void *data) +{ + struct item *item; + + item = eina_list_nth(s_info.pd_open_pending_list, 0); + if (!item) + goto cleanout; + + if (s_info.update) + return ECORE_CALLBACK_RENEW; + + s_info.pd_open_pending_list = eina_list_remove(s_info.pd_open_pending_list, item); + DbgPrint("Consuming pended item: %s\n", item->inst->id); + /*! + * \note + * To prevent from checking the is_updated function + */ + (void)updator_cb(item); + if (s_info.pd_open_pending_list) + return ECORE_CALLBACK_RENEW; + +cleanout: + s_info.pd_open_pending_timer = NULL; + DbgPrint("open pd pending list exhausted\n"); + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool pended_cmd_consumer_cb(void *data) +{ + struct item *item; + + item = eina_list_nth(s_info.pending_list, 0); + if (!item) + goto cleanout; + + if (s_info.update || pd_is_opened(item->inst->item->pkgname) < 0) + return ECORE_CALLBACK_RENEW; + + s_info.pending_list = eina_list_remove(s_info.pending_list, item); + DbgPrint("Consuming pended item: %s\n", item->inst->id); + /*! + * \note + * To prevent from checking the is_updated function + */ + (void)updator_cb(item); + if (s_info.pending_list) + return ECORE_CALLBACK_RENEW; + +cleanout: + s_info.pending_timer = NULL; + s_info.pending_timer_freezed = 0; + DbgPrint("pending list exhausted\n"); + return ECORE_CALLBACK_CANCEL; +} + +static inline int activate_pending_consumer(void) +{ + if (s_info.pending_timer) + return 0; + + s_info.pending_timer = ecore_timer_add(0.000001f, pended_cmd_consumer_cb, NULL); + if (!s_info.pending_timer) { + ErrPrint("Failed to add a new pended command consumer\n"); + return -EFAULT; + } + + /*! + * Do not increase the freezed counter. + * Just freeze the timer. + */ + if (s_info.pending_timer_freezed) { + DbgPrint("Pending timer created and freezed\n"); + ecore_timer_freeze(s_info.pending_timer); + } + + return 0; +} + +static inline void deactivate_pending_consumer(void) +{ + if (!s_info.pending_timer) + return; + + ecore_timer_del(s_info.pending_timer); + s_info.pending_timer = NULL; + s_info.pending_timer_freezed = 0; + DbgPrint("Clear the pending timer\n"); +} + +static inline void deactivate_pd_open_pending_consumer(void) +{ + if (!s_info.pd_open_pending_timer) + return; + + ecore_timer_del(s_info.pd_open_pending_timer); + s_info.pd_open_pending_timer = NULL; + DbgPrint("Clear the open_pd_pending timer\n"); +} + +static inline int activate_pd_open_pending_consumer(void) +{ + if (s_info.pd_open_pending_timer) + return 0; + + s_info.pd_open_pending_timer = ecore_timer_add(0.000001f, pd_open_pended_cmd_consumer_cb, NULL); + if (!s_info.pd_open_pending_timer) { + ErrPrint("Failed to add a new pended command consumer\n"); + return -EFAULT; + } + + return 0; +} + +static inline void migrate_to_pd_open_pending_list(const char *pkgname) +{ + Eina_List *l; + Eina_List *n; + struct item *item; + int cnt = 0; + + EINA_LIST_FOREACH_SAFE(s_info.pending_list, l, n, item) { + if (strcmp(pkgname, item->inst->item->pkgname)) + continue; + + s_info.pending_list = eina_list_remove(s_info.pending_list, item); + s_info.pd_open_pending_list = eina_list_append(s_info.pd_open_pending_list, item); + cnt++; + } + + if (s_info.pd_open_pending_list) + activate_pd_open_pending_consumer(); + + if (!s_info.pending_list) + deactivate_pending_consumer(); + + DbgPrint("%d items are migrated\n", cnt); +} + +static inline void migrate_to_pending_list(const char *pkgname) +{ + Eina_List *l; + Eina_List *n; + struct item *item; + int cnt = 0; + + EINA_LIST_FOREACH_SAFE(s_info.pd_open_pending_list, l, n, item) { + if (strcmp(pkgname, item->inst->item->pkgname)) + continue; + + s_info.pd_open_pending_list = eina_list_remove(s_info.pd_open_pending_list, item); + s_info.pending_list = eina_list_append(s_info.pending_list, item); + cnt++; + } + + if (s_info.pending_list) + activate_pending_consumer(); + + if (!s_info.pd_open_pending_list) + deactivate_pd_open_pending_consumer(); + + DbgPrint("%d items are migrated\n", cnt); +} + +static inline int append_pending_list(struct item *item) +{ + if (pd_is_opened(item->inst->item->pkgname) == 1) { + if (eina_list_data_find(s_info.pd_open_pending_list, item) == item) { + DbgPrint("Already pended - %s\n", item->inst->item->pkgname); + return -EEXIST; + } + + if (activate_pd_open_pending_consumer() < 0) + return -EFAULT; + + s_info.pd_open_pending_list = eina_list_append(s_info.pd_open_pending_list, item); + } else { + if (eina_list_data_find(s_info.pending_list, item) == item) { + DbgPrint("Already pended - %s\n", item->inst->item->pkgname); + return -EEXIST; + } + + if (activate_pending_consumer() < 0) + return -EFAULT; + + s_info.pending_list = eina_list_append(s_info.pending_list, item); + } + return 0; +} + +static inline void timer_thaw(struct item *item) +{ + struct timeval tv; + double pending; + double compensate; + double sleep_time; + + ecore_timer_thaw(item->timer); + + if (item->sleep_at == 0.0f) + return; + + pending = ecore_timer_pending_get(item->timer); + + if (gettimeofday(&tv, NULL) < 0) { + ErrPrint("Failed to get timeofday: %s\n", strerror(errno)); + return; + } + sleep_time = ((double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f) - item->sleep_at; + compensate = 60.0f - ((double)(tv.tv_sec % 60) + ((double)tv.tv_usec / 1000000.0f)); + + ecore_timer_delay(item->timer, compensate - pending); + DbgPrint("Compensate timer: %lf\n", compensate - pending); + + if (sleep_time > pending) { + DbgPrint("Append pending list to update content\n"); + (void)append_pending_list(item); + } + + item->sleep_at = 0.0f; +} + +static inline void timer_freeze(struct item *item) +{ + struct timeval tv; + ecore_timer_freeze(item->timer); + + gettimeofday(&tv, NULL); + item->sleep_at = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f; +} + +static inline void update_monitor_cnt(struct item *item) +{ + double now; + double interval; + + now = util_timestamp(); + interval = now - item->update_interval; + + /*! + * \note + * If the content update is processed in too short time, + * don't increase the monitor counter, instead of it + * set the heavy updating flag. + * And handling this heavy updating from the + * file update callback. + */ + if (interval >= MINIMUM_UPDATE_INTERVAL) + item->monitor_cnt++; + else + item->heavy_updating = 1; + + item->update_interval = now; +} + +static inline Eina_List *find_item(struct instance *inst) +{ + Eina_List *l; + struct item *item; + + EINA_LIST_FOREACH(s_info.item_list, l, item) { + if (item->inst == inst) + return l; + } + + return NULL; +} + +static inline int output_handler(struct item *item) +{ + int invalid = 0; + + item->monitor_cnt--; + if (item->monitor_cnt < 0 || item->heavy_updating) { + if (!item->heavy_updating) { + WarnPrint("%s has invalid monitor_cnt\n", item->inst->id); + invalid = 1; + } else { + item->heavy_updating = 0; /* Reset flag */ + } + + item->monitor_cnt = 0; + } + + if (item->monitor_cnt == 0) { + if (!invalid) + fault_unmark_call(item->inst->item->pkgname, item->inst->id, "update,crashed", NO_ALARM); + + if (item->monitor) { + ecore_timer_del(item->monitor); + item->monitor = NULL; + } + + if (s_info.update == item) + s_info.update = NULL; + + if (item->deleteme) { + provider_send_deleted(item->inst->item->pkgname, item->inst->id); + (void)so_destroy(item->inst); + free(item); + return EXIT_FAILURE; + } + } + + return EXIT_SUCCESS; +} + +static int desc_updated_cb(const char *filename, void *data, int over) +{ + struct item *item; + + if (over) + WarnPrint("Event Q overflow\n"); + + item = data; + + DbgPrint("DESC %s is updated\n", filename); + provider_send_desc_updated(item->inst->item->pkgname, item->inst->id, filename); + return EXIT_SUCCESS; +} + +static int file_updated_cb(const char *filename, void *data, int over) +{ + struct item *item; + int w; + int h; + double priority; + char *content; + char *title; + + if (over) + WarnPrint("Event Q overflow\n"); + + item = data; + + (void)so_get_output_info(item->inst, &w, &h, &priority, &content, &title); + provider_send_updated(item->inst->item->pkgname, item->inst->id, + item->inst->w, item->inst->h, item->inst->priority, content, title); + + return output_handler(item); +} + +static inline int clear_from_pd_open_pending_list(struct item *item) +{ + Eina_List *l; + struct item *tmp; + + EINA_LIST_FOREACH(s_info.pd_open_pending_list, l, tmp) { + if (tmp != item) + continue; + + s_info.pd_open_pending_list = eina_list_remove_list(s_info.pd_open_pending_list, l); + if (!s_info.pd_open_pending_list) + deactivate_pd_open_pending_consumer(); + return 0; + } + + return -ENOENT; +} + +static inline int clear_from_pending_list(struct item *item) +{ + Eina_List *l; + struct item *tmp; + + EINA_LIST_FOREACH(s_info.pending_list, l, tmp) { + if (tmp != item) + continue; + + s_info.pending_list = eina_list_remove_list(s_info.pending_list, l); + if (!s_info.pending_list) + deactivate_pending_consumer(); + return 0; + } + + return -ENOENT; +} + +static Eina_Bool update_timeout_cb(void *data) +{ + struct item *item; + + item = data; + + DbgPrint("UPDATE TIMEOUT ========> %s - %s\n", item->inst->item->pkgname, item->inst->id); + + if (s_info.update != item) + ErrPrint("Updating item is not matched\n"); + + fault_unmark_call(item->inst->item->pkgname, item->inst->id, "update,crashed", NO_ALARM); + fault_mark_call(item->inst->item->pkgname, item->inst->id, "update,timeout", NO_ALARM, DEFAULT_LIFE_TIMER); + s_info.update = NULL; + + exit(ETIME); + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool updator_cb(void *data) +{ + struct item *item; + int ret; + + item = data; + + if (item->monitor) {/*!< If this item is already in update process */ + return ECORE_CALLBACK_RENEW; + } + + ret = so_is_updated(item->inst); + if (ret <= 0) { + if (so_need_to_destroy(item->inst) == NEED_TO_DESTROY) { + provider_send_deleted(item->inst->item->pkgname, item->inst->id); + lb_destroy(item->inst->item->pkgname, item->inst->id); + + ecore_timer_del(item->timer); + item->timer = NULL; + return ECORE_CALLBACK_CANCEL; + } + + return ECORE_CALLBACK_RENEW; + } + + if (s_info.update || pd_is_opened(item->inst->item->pkgname) < 0) { + (void)append_pending_list(item); + return ECORE_CALLBACK_RENEW; + } + + item->monitor = ecore_timer_add(item->inst->item->timeout, update_timeout_cb, item); + if (!item->monitor) { + ErrPrint("Failed to add update monitor %s(%s):%d\n", + item->inst->item->pkgname, item->inst->id, item->inst->item->timeout); + return ECORE_CALLBACK_RENEW; + } + + /*! + * \note + * Counter of the event monitor is only used for asynchronous content updating, + * So reset it to 1 from here because the async updating is started now, + * even if it is accumulated by other event function before this. + */ + item->monitor_cnt = 1; + + s_info.update = item; + + ret = so_update(item->inst); + if (ret < 0) { + item->monitor_cnt--; + + ecore_timer_del(item->monitor); + item->monitor = NULL; + s_info.update = NULL; + return ECORE_CALLBACK_RENEW; + } + + /*! + * \note + * While waiting the Callback function call, + * Add this for finding the crash + */ + fault_mark_call(item->inst->item->pkgname, item->inst->id, "update,crashed", NO_ALARM, DEFAULT_LIFE_TIMER); + + if (ret & NEED_TO_SCHEDULE) { + (void)append_pending_list(item); + } + + if (ret & OUTPUT_UPDATED) + update_monitor_cnt(item); + + return ECORE_CALLBACK_RENEW; +} + +static inline void update_monitor_del(struct item *item) +{ + char *tmp; + int len; + + update_monitor_del_update_cb(util_uri_to_path(item->inst->id), file_updated_cb); + + len = strlen(util_uri_to_path(item->inst->id)) + strlen(".desc") + 1; + tmp = malloc(len); + if (!tmp) { + ErrPrint("Heap: %s (%s.desc)\n", strerror(errno), util_uri_to_path(item->inst->id)); + return; + } + + snprintf(tmp, len, "%s.desc", util_uri_to_path(item->inst->id)); + update_monitor_del_update_cb(tmp, desc_updated_cb); + free(tmp); +} + +static inline int add_desc_update_monitor(struct item *item) +{ + char *filename; + int len; + + len = strlen(util_uri_to_path(item->inst->id)) + strlen(".desc") + 1; + filename = malloc(len); + if (!filename) { + ErrPrint("Heap: %s (%s.desc)\n", strerror(errno), util_uri_to_path(item->inst->id)); + return -ENOMEM; + } + + snprintf(filename, len, "%s.desc", util_uri_to_path(item->inst->id)); + DbgPrint("Add DESC monitor: %s\n", filename); + return update_monitor_add_update_cb(filename, desc_updated_cb, item); +} + +static inline int add_file_update_monitor(struct item *item) +{ + char *filename; + + filename = strdup(util_uri_to_path(item->inst->id)); + if (!filename) { + ErrPrint("Heap: %s (%s)\n", strerror(errno), item->inst->id); + return -ENOMEM; + } + + return update_monitor_add_update_cb(filename, file_updated_cb, item); +} + +static inline int update_monitor_add(struct item *item) +{ + add_file_update_monitor(item); + add_desc_update_monitor(item); + return 0; +} + +HAPI int lb_init(void) +{ + return 0; +} + +HAPI int lb_fini(void) +{ + Eina_List *l; + Eina_List *n; + struct item *item; + + deactivate_pending_consumer(); + deactivate_pd_open_pending_consumer(); + + EINA_LIST_FREE(s_info.pd_open_pending_list, item); + EINA_LIST_FREE(s_info.pending_list, item); + + EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) { + provider_send_deleted(item->inst->item->pkgname, item->inst->id); + lb_destroy(item->inst->item->pkgname, item->inst->id); + } + + return 0; +} + +/*! + * \note + * Exported API for each liveboxes. + */ +const char *livebox_find_pkgname(const char *filename) +{ + Eina_List *l; + struct item *item; + + EINA_LIST_FOREACH(s_info.item_list, l, item) { + if (!strcmp(item->inst->id, filename)) + return item->inst->item->pkgname; + } + + return NULL; +} + +HAPI int lb_open_pd(const char *pkgname) +{ + Eina_List *l; + char *tmp; + + EINA_LIST_FOREACH(s_info.pd_list, l, tmp) { + if (!strcmp(pkgname, tmp)) + return 0; + } + + tmp = strdup(pkgname); + if (!tmp) { + ErrPrint("Heap: %s\n", strerror(errno)); + return -ENOMEM; + } + + if (!s_info.pd_list) + pending_timer_freeze(); + + s_info.pd_list = eina_list_append(s_info.pd_list, tmp); + + /*! + * Find all instances from the pending list. + * Move them to pd_open_pending_timer + */ + migrate_to_pd_open_pending_list(pkgname); + return 0; +} + +HAPI int lb_close_pd(const char *pkgname) +{ + Eina_List *l; + Eina_List *n; + char *tmp; + + EINA_LIST_FOREACH_SAFE(s_info.pd_list, l, n, tmp) { + if (strcmp(tmp, pkgname)) + continue; + + s_info.pd_list = eina_list_remove(s_info.pd_list, tmp); + free(tmp); + + if (!s_info.pd_list) + pending_timer_thaw(); + + /*! + * Move all items in pd_open_pending_list + * to pending_list. + */ + migrate_to_pending_list(pkgname); + return 0; + } + + return -ENOENT; +} + +HAPI int lb_create(const char *pkgname, const char *id, const char *content_info, int timeout, int has_livebox_script, double period, const char *cluster, const char *category, int *w, int *h, double *priority, int skip_need_to_create, const char *abi, char **out_content, char **out_title) +{ + struct instance *inst; + struct item *item; + int ret; + int create_ret; + int need_to_create; + + need_to_create = 0; + *out_content = NULL; + *out_title = NULL; + + inst = so_find_instance(pkgname, id); + if (inst) { + DbgPrint("Instance is already exists [%s - %s] content[%s], cluster[%s], category[%s], abi[%s]\n", pkgname, id, content_info, cluster, category, abi); + return 0; + } + + if (!skip_need_to_create) { + ret = so_create_needed(pkgname, cluster, category, abi); + if (ret != NEED_TO_CREATE) + return -EPERM; + + need_to_create = 1; + } + + item = malloc(sizeof(*item)); + if (!item) { + ErrPrint("Heap: %s (%s - %s, content[%s], cluster[%s], category[%s], abi[%s])\n", strerror(errno), pkgname, id, content_info, cluster, category, abi); + return -ENOMEM; + } + + item->monitor = NULL; + item->monitor_cnt = 0; + item->deleteme = 0; + item->update_interval = 0.0f; + item->heavy_updating = 0; + item->is_paused = 0; + item->sleep_at = 0.0f; + + create_ret = so_create(pkgname, id, content_info, timeout, has_livebox_script, cluster, category, abi, &inst); + if (create_ret < 0) { + free(item); + + *w = 0; + *h = 0; + *priority = 0.0f; + return create_ret; + } + + item->inst = inst; + + if (period > 0.0f && !s_info.secured) { + item->timer = util_timer_add(period, updator_cb, item); + if (!item->timer) { + ErrPrint("Failed to add timer (%s - %s, content[%s], cluster[%s], category[%s], abi[%s]\n", pkgname, id, content_info, cluster, category, abi); + so_destroy(inst); + free(item); + return -EFAULT; + } + + if (s_info.paused) + timer_freeze(item); + } else { + DbgPrint("Local update timer is disabled: %lf (%d)\n", period, s_info.secured); + item->timer = NULL; + } + + ret = update_monitor_add(item); + if (ret < 0) { + so_destroy(inst); + if (item->timer) + ecore_timer_del(item->timer); + free(item); + return ret; + } + + s_info.item_list = eina_list_append(s_info.item_list, item); + + if (create_ret & NEED_TO_SCHEDULE) { + DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname); + (void)append_pending_list(item); + } + + if (create_ret & OUTPUT_UPDATED) { + char *tmp_content; + char *tmp_title; + + update_monitor_cnt(item); + /*! + * \note + * To send a output info, get the info forcely. + * but the output file monitor will do this again + * + * This function will set the tmp_content and tmp_title + * even if it has no updates on the content, title, + * it will set them to NULL. + */ + (void)so_get_output_info(inst, w, h, priority, &tmp_content, &tmp_title); + + /*! + * \note + * These two values will be released by the provider library. + */ + if (tmp_content) { + *out_content = strdup(tmp_content); + if (!*out_content) + ErrPrint("Heap: %s\n", strerror(errno)); + } + + if (tmp_title) { + *out_title = strdup(tmp_title); + if (!*out_title) + ErrPrint("Heap: %s\n", strerror(errno)); + } + } + + *w = inst->w; + *h = inst->h; + *priority = inst->priority; + return need_to_create; +} + +HAPI int lb_destroy(const char *pkgname, const char *id) +{ + Eina_List *l; + struct instance *inst; + struct item *item; + int ret; + + inst = so_find_instance(pkgname, id); + if (!inst) { + ErrPrint("Instance %s - %s is not created\n", pkgname, id); + return -EINVAL; + } + + l = find_item(inst); + if (!l) { + ErrPrint("Instance is not found (%s - %s)\n", pkgname, id); + return -ENOENT; + } + + item = eina_list_data_get(l); + s_info.item_list = eina_list_remove_list(s_info.item_list, l); + + if (s_info.update == item) + s_info.update = NULL; + + if (item->timer) { + clear_from_pd_open_pending_list(item); + clear_from_pending_list(item); + ecore_timer_del(item->timer); + item->timer = NULL; + + if (item->monitor) + item->deleteme = 1; + else + update_monitor_del(item); + } + + if (!item->monitor) { + free(item); + ret = so_destroy(inst); + } + + return 0; +} + +HAPI int lb_resize(const char *pkgname, const char *id, int w, int h) +{ + Eina_List *l; + struct instance *inst; + struct item *item; + int ret; + + inst = so_find_instance(pkgname, id); + if (!inst) { + ErrPrint("Instance %s - %s is not created (%dx%d)\n", pkgname, id, w, h); + return -EINVAL; + } + + l = find_item(inst); + if (!l) { + ErrPrint("Instance is not found (%s - %s, %dx%d)\n", pkgname, id, w, h); + return -ENOENT; + } + + item = eina_list_data_get(l); + + ret = so_resize(inst, w, h); + if (ret < 0) + return ret; + + if (ret & NEED_TO_SCHEDULE) { + DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname); + (void)append_pending_list(item); + } + + if (ret & OUTPUT_UPDATED) + update_monitor_cnt(item); + + return 0; +} + +HAPI char *lb_pinup(const char *pkgname, const char *id, int pinup) +{ + struct instance *inst; + char *ret; + + inst = so_find_instance(pkgname, id); + if (!inst) { + ErrPrint("Instance %s - %s is not found (pinup[%d])\n", pkgname, id, pinup); + return NULL; + } + + ret = so_pinup(inst, pinup); + return ret; +} + +HAPI int lb_set_period(const char *pkgname, const char *id, double period) +{ + Eina_List *l; + struct instance *inst; + struct item *item; + + inst = so_find_instance(pkgname, id); + if (!inst) { + ErrPrint("Instance %s - %s is not found (period[%lf])\n", pkgname, id, period); + return -EINVAL; + } + + l = find_item(inst); + if (!l) { + ErrPrint("Instance is not found (%s - %s, period[%lf])\n", pkgname, id, period); + return -ENOENT; + } + + item = eina_list_data_get(l); + + if (period <= 0.0f) { + if (item->timer) { + ecore_timer_del(item->timer); + item->timer = NULL; + } + } else { + if (item->timer) { + util_timer_interval_set(item->timer, period); + } else if (!s_info.secured) { + item->timer = util_timer_add(period, updator_cb, item); + if (!item->timer) { + ErrPrint("Failed to add timer (%s - %s)\n", pkgname, id); + return -EFAULT; + } + + if (s_info.paused) + timer_freeze(item); + } + } + + return 0; +} + +HAPI int lb_clicked(const char *pkgname, const char *id, const char *event, double timestamp, double x, double y) +{ + Eina_List *l; + struct instance *inst; + struct item *item; + int ret; + + inst = so_find_instance(pkgname, id); + if (!inst) { + ErrPrint("Instance %s - %s is not exists (event[%s])\n", pkgname, id, event); + return -EINVAL; + } + + l = find_item(inst); + if (!l) { + ErrPrint("Instance is not found (%s - %s, event[%s])\n", pkgname, id, event); + return -ENOENT; + } + + item = eina_list_data_get(l); + + ret = so_clicked(inst, event, timestamp, x, y); + if (ret < 0) + return ret; + + if (ret & NEED_TO_SCHEDULE) { + DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname); + (void)append_pending_list(item); + } + + if (ret & OUTPUT_UPDATED) + update_monitor_cnt(item); + + return 0; +} + +HAPI int lb_script_event(const char *pkgname, const char *id, const char *emission, const char *source, struct event_info *event_info) +{ + Eina_List *l; + struct instance *inst; + struct item *item; + int ret; + + inst = so_find_instance(pkgname, id); + if (!inst) { + ErrPrint("Instance %s - %s is not exists (emission[%s], source[%s])\n", pkgname, id, emission, source); + return -EINVAL; + } + + l = find_item(inst); + if (!l) { + ErrPrint("Instance is not found (%s - %s, emissino[%s], source[%s])\n", pkgname, id, emission, source); + return -ENOENT; + } + + item = eina_list_data_get(l); + + ret = so_script_event(inst, emission, source, event_info); + if (ret < 0) + return ret; + + if (ret & NEED_TO_SCHEDULE) { + DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname); + (void)append_pending_list(item); + } + + if (ret & OUTPUT_UPDATED) + update_monitor_cnt(item); + + return 0; +} + +HAPI int lb_is_pinned_up(const char *pkgname, const char *id) +{ + Eina_List *l; + struct instance *inst; + struct item *item; + int ret; + + inst = so_find_instance(pkgname, id); + if (!inst) { + ErrPrint("Instance %s - %s is not created\n", pkgname, id); + return -EINVAL; + } + + l = find_item(inst); + if (!l) { + ErrPrint("Instance is not found(%s - %s)\n", pkgname, id); + return -ENOENT; + } + + item = eina_list_data_get(l); + /*! + * NOTE: + * item is not used. + * Maybe this is not neccessary for this operation + */ + ret = so_is_pinned_up(inst); + return ret; +} + +HAPI int lb_change_group(const char *pkgname, const char *id, const char *cluster, const char *category) +{ + Eina_List *l; + struct instance *inst; + struct item *item; + int ret; + + inst = so_find_instance(pkgname, id); + if (!inst) { + ErrPrint("Instance %s - %s is not created (cluster[%s], category[%s])\n", pkgname, id, cluster, category); + return -EINVAL; + } + + l = find_item(inst); + if (!l) { + ErrPrint("Instance is not found(%s - %s, cluster[%s], category[%s])\n", pkgname, id, cluster, category); + return -ENOENT; + } + + item = eina_list_data_get(l); + + ret = so_change_group(inst, cluster, category); + if (ret < 0) + return ret; + + if (ret & NEED_TO_SCHEDULE) { + DbgPrint("%s Returns NEED_TO_SCHEDULE\n", pkgname); + (void)append_pending_list(item); + } + + if (ret & OUTPUT_UPDATED) + update_monitor_cnt(item); + + return 0; +} + +static inline int lb_sys_event(struct instance *inst, struct item *item, int event) +{ + int ret; + + ret = so_sys_event(inst, event); + if (ret < 0) + return ret; + + if (ret & NEED_TO_SCHEDULE) + (void)append_pending_list(item); + + if (ret & OUTPUT_UPDATED) + update_monitor_cnt(item); + + return 0; +} + +HAPI int lb_system_event(const char *pkgname, const char *id, int event) +{ + Eina_List *l; + struct instance *inst; + struct item *item; + + inst = so_find_instance(pkgname, id); + if (!inst) { + ErrPrint("instance %s - %s is not created\n"); + return -EINVAL; + } + + l = find_item(inst); + if (!l) { + ErrPrint("Instance is not found(%s - %s)\n", pkgname, id); + return -ENOENT; + } + + item = eina_list_data_get(l); + return lb_sys_event(inst, item, event); +} + +HAPI int lb_update(const char *pkgname, const char *id) +{ + Eina_List *l; + struct instance *inst; + struct item *item; + + inst = so_find_instance(pkgname, id); + if (!inst) { + ErrPrint("Instance %s - %s is not created\n", pkgname, id); + return -EINVAL; + } + + l = find_item(inst); + if (!l) { + ErrPrint("Instance is not found(%s - %s)\n", pkgname, id); + return -ENOENT; + } + + item = eina_list_data_get(l); + (void)append_pending_list(item); + return 0; +} + +HAPI int lb_update_all(const char *pkgname, const char *cluster, const char *category) +{ + Eina_List *l; + Eina_List *n; + struct item *item; + + DbgPrint("Update content for %s\n", pkgname ? pkgname : "(all)"); + EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) { + if (item->deleteme) + continue; + + if (cluster && strcasecmp(item->inst->cluster, cluster)) + continue; + + if (category && strcasecmp(item->inst->category, category)) + continue; + + if (pkgname && strlen(pkgname)) { + if (!strcmp(item->inst->item->pkgname, pkgname)) { + (void)append_pending_list(item); + } + } else { + (void)append_pending_list(item); + } + } + + return 0; +} + +HAPI int lb_system_event_all(int event) +{ + Eina_List *l; + Eina_List *n; + struct item *item; + + EINA_LIST_FOREACH_SAFE(s_info.item_list, l, n, item) { + if (item->deleteme) + continue; + + DbgPrint("System event for %s (%d)\n", item->inst->id, event); + lb_sys_event(item->inst, item, event); + } + + return 0; +} + +HAPI void lb_pause_all(void) +{ + Eina_List *l; + struct item *item; + + s_info.paused = 1; + + pending_timer_freeze(); + + EINA_LIST_FOREACH(s_info.item_list, l, item) { + if (item->deleteme) { + DbgPrint("Instance %s skip timer pause (deleteme)\n", item->inst->item->pkgname); + continue; + } + + if (item->is_paused) { + DbgPrint("Instance %s is already paused\n", item->inst->id); + continue; + } + + if (item->timer) { + DbgPrint("Instance %s freeze timer\n", item->inst->item->pkgname); + timer_freeze(item); + } else { + DbgPrint("Instance %s has no timer\n", item->inst->item->pkgname); + } + + lb_sys_event(item->inst, item, LB_SYS_EVENT_PAUSED); + } +} + +HAPI void lb_resume_all(void) +{ + Eina_List *l; + struct item *item; + + s_info.paused = 0; + + pending_timer_thaw(); + + EINA_LIST_FOREACH(s_info.item_list, l, item) { + if (item->deleteme) { + DbgPrint("Instance %s skip timer resume (deleteme)\n", item->inst->item->pkgname); + continue; + } + + if (item->is_paused) { + DbgPrint("Instance %s is still paused\n", item->inst->id); + continue; + } + + if (item->timer) { + DbgPrint("Instance %s resume timer\n", item->inst->item->pkgname); + timer_thaw(item); + } + + lb_sys_event(item->inst, item, LB_SYS_EVENT_RESUMED); + } +} + +HAPI int lb_pause(const char *pkgname, const char *id) +{ + struct instance *inst; + Eina_List *l; + struct item *item; + + inst = so_find_instance(pkgname, id); + if (!inst) + return -EINVAL; + + l = find_item(inst); + if (!l) { + ErrPrint("Instance is not found (%s - %s)\n", pkgname, id); + return -ENOENT; + } + + item = eina_list_data_get(l); + if (!item) + return -EFAULT; + + if (item->deleteme) { + DbgPrint("Instance %s will be deleted (%s)\n", item->inst->item->pkgname, item->inst->id); + return -EBUSY; + } + + item->is_paused = 1; + + if (s_info.paused) { + DbgPrint("Already paused: %s\n", item->inst->id); + return 0; + } + + if (item->timer) + timer_freeze(item); + + lb_sys_event(inst, item, LB_SYS_EVENT_PAUSED); + + return 0; +} + +HAPI int lb_resume(const char *pkgname, const char *id) +{ + struct instance *inst; + Eina_List *l; + struct item *item; + + inst = so_find_instance(pkgname, id); + if (!inst) + return -EINVAL; + + l = find_item(inst); + if (!l) { + ErrPrint("Instance is not found (%s - %s)\n", pkgname, id); + return -ENOENT; + } + + item = eina_list_data_get(l); + if (!item) + return -EFAULT; + + if (item->deleteme) { + DbgPrint("Instance %s will be deleted (%s)\n", item->inst->item->pkgname, item->inst->id); + return -EBUSY; + } + + item->is_paused = 0; + + if (s_info.paused) { + DbgPrint("Instance %s is still paused\n", item->inst->id); + return 0; + } + + if (item->timer) + timer_thaw(item); + + lb_sys_event(inst, item, LB_SYS_EVENT_RESUMED); + return 0; +} + +HAPI void lb_turn_secured_on(void) +{ + s_info.secured = 1; +} + +/* End of a file */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..4176a63 --- /dev/null +++ b/src/main.c @@ -0,0 +1,298 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "critical_log.h" +#include "debug.h" +#include "conf.h" +#include "fault.h" +#include "update_monitor.h" +#include "client.h" +#include "util.h" +#include "so_handler.h" +#include "lb.h" + +/*! + * \NOTE + * Undocumented API + */ +extern void evas_common_font_flush(void); +extern int evas_common_font_cache_get(void); +extern void evas_common_font_cache_set(int size); + +#define TEXT_CLASS "slp" +#define TEXT_SIZE -100 + +static struct info { + Ecore_Event_Handler *property_handler; + int heap_monitor; +} s_info = { + .property_handler = NULL, + .heap_monitor = 0, +}; + +static Eina_Bool update_font_cb(void *data) +{ + lb_system_event_all(LB_SYS_EVENT_FONT_CHANGED); + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool property_cb(void *data, int type, void *event) +{ + Ecore_X_Event_Window_Property *info = (Ecore_X_Event_Window_Property *)event; + + if (info->atom == ecore_x_atom_get("FONT_TYPE_change") || info->atom == ecore_x_atom_get("BADA_FONT_change")) { + Eina_List *list; + char *text; + char *font; + int cache; + + font = vconf_get_str("db/setting/accessibility/font_name"); + if (!font) + return ECORE_CALLBACK_PASS_ON; + + cache = evas_common_font_cache_get(); + evas_common_font_cache_set(0); + evas_common_font_flush(); + + list = edje_text_class_list(); + EINA_LIST_FREE(list, text) { + if (!strncasecmp(text, TEXT_CLASS, strlen(TEXT_CLASS))) { + edje_text_class_del(text); + edje_text_class_set(text, font, TEXT_SIZE); + DbgPrint("Update text class %s (%s, %d)\n", text, font, TEXT_SIZE); + } else { + DbgPrint("Skip text class %s\n", text); + } + } + + evas_common_font_cache_set(cache); + free(font); + + /*! + * \NOTE + * Try to update all liveboxes + */ + if (!ecore_timer_add(0.1f, update_font_cb, NULL)) { + ErrPrint("Failed to add timer for updating fonts\n"); + lb_system_event_all(LB_SYS_EVENT_FONT_CHANGED); + } + } + + return ECORE_CALLBACK_PASS_ON; +} + +static bool app_create(void *data) +{ + int ret; + + ret = conf_loader(); + DbgPrint("Configureation manager is initiated: %d\n", ret); + + if (COM_CORE_THREAD) + setenv("PROVIDER_COM_CORE_THREAD", "true", 0); + else + setenv("PROVIDER_COM_CORE_THREAD", "false", 0); + + s_info.property_handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, property_cb, NULL); + if (!s_info.property_handler) + ErrPrint("Failed to add a property change event handler\n"); + + ret = livebox_service_init(); + DbgPrint("Livebox service init: %d\n", ret); + + /* + * \note + * Slave is not able to initiate system, before + * receive its name from the master + * + * So create callback doesn't do anything. + */ + ret = fault_init(); + DbgPrint("Crash recover is initiated: %d\n", ret); + ret = update_monitor_init(); + DbgPrint("Content update monitor is initiated: %d\n", ret); + + return TRUE; +} + +static void app_terminate(void *data) +{ + int ret; + + ret = update_monitor_fini(); + DbgPrint("Content update monitor is finalized: %d\n", ret); + ret = fault_fini(); + DbgPrint("Crash recover is finalized: %d\n", ret); + + ret = client_fini(); + DbgPrint("client finalized: %d\n", ret); + + ret = livebox_service_fini(); + DbgPrint("livebox service fini: %d\n", ret); + + ecore_event_handler_del(s_info.property_handler); + s_info.property_handler = NULL; + + return; +} + +static void app_pause(void *data) +{ + /* Will not be invoked */ + return; +} + +static void app_resume(void *data) +{ + /* Will not be invoked */ + return; +} + +static void app_language_changed(void *data) +{ + lb_system_event_all(LB_SYS_EVENT_LANG_CHANGED); +} + +static void app_service(service_h service, void *data) +{ + int ret; + char *name; + char *secured; + static int initialized = 0; + + if (initialized) { + ErrPrint("Already initialized\n"); + return; + } + + ret = service_get_extra_data(service, "name", &name); + if (ret != SERVICE_ERROR_NONE) { + ErrPrint("Name is not valid\n"); + return; + } + + ret = service_get_extra_data(service, "secured", &secured); + if (ret != SERVICE_ERROR_NONE) { + ErrPrint("Secured is not valid\n"); + return; + } + + if (!!strcasecmp(secured, "true")) { + if (s_info.heap_monitor) { + heap_monitor_start(); + /* Add GUARD */ + // heap_monitor_add_target("/usr/apps/org.tizen."EXEC_NAME"/bin/"EXEC_NAME); + } + } else { + /* Don't use the update timer */ + lb_turn_secured_on(); + } + + DbgPrint("Name assigned: %s\n", name); + DbgPrint("Secured: %s\n", secured); + ret = client_init(name); + + initialized = 1; + return; +} + +void (*__malloc_initialize_hook)(void) = heap_monitor_init; + +#if defined(_ENABLE_MCHECK) +static inline void mcheck_cb(enum mcheck_status status) +{ + char *ptr; + + ptr = util_get_current_module(NULL); + + switch (status) { + case MCHECK_DISABLED: + ErrPrint("[DISABLED] Heap incosistency detected: %s\n", ptr); + break; + case MCHECK_OK: + ErrPrint("[OK] Heap incosistency detected: %s\n", ptr); + break; + case MCHECK_HEAD: + ErrPrint("[HEAD] Heap incosistency detected: %s\n", ptr); + break; + case MCHECK_TAIL: + ErrPrint("[TAIL] Heap incosistency detected: %s\n", ptr); + break; + case MCHECK_FREE: + ErrPrint("[FREE] Heap incosistency detected: %s\n", ptr); + break; + default: + break; + } +} +#endif + +int main(int argc, char *argv[]) +{ + int ret; + app_event_callback_s event_callback; + const char *option; + +#if defined(_ENABLE_MCHECK) + mcheck(mcheck_cb); +#endif + option = getenv("PROVIDER_DISABLE_CALL_OPTION"); + if (option && !strcasecmp(option, "true")) + fault_disable_call_option(); + + option = getenv("PROVIDER_HEAP_MONITOR_START"); + if (option && !strcasecmp(option, "true")) + s_info.heap_monitor = 1; + + critical_log_init(util_basename(argv[0])); + event_callback.create = app_create; + event_callback.terminate = app_terminate; + event_callback.pause = app_pause; + event_callback.resume = app_resume; + event_callback.service = app_service; + event_callback.low_memory = NULL; + event_callback.low_battery = NULL; + event_callback.device_orientation = NULL; + event_callback.language_changed = app_language_changed; + ret = app_efl_main(&argc, &argv, &event_callback, NULL); + critical_log_fini(); + return ret; +} + +/* End of a file */ diff --git a/src/so_handler.c b/src/so_handler.c new file mode 100644 index 0000000..941f416 --- /dev/null +++ b/src/so_handler.c @@ -0,0 +1,915 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include /* dlopen */ +#include /* malloc, free */ +#include /* strcmp */ + +#include +#include +#include +#include +#include + +#include "critical_log.h" +#include "debug.h" +#include "so_handler.h" +#include "fault.h" +#include "conf.h" +#include "util.h" + +int errno; + +static struct info { + Eina_List *livebox_list; +} s_info = { + .livebox_list = NULL, +}; + +static inline struct so_item *find_livebox(const char *pkgname) +{ + Eina_List *l; + struct so_item *item; + + EINA_LIST_FOREACH(s_info.livebox_list, l, item) { + if (!strcmp(item->pkgname, pkgname)) + return item; + } + + return NULL; +} + +static inline char *so_adaptor_alloc(const char *abi) +{ + /* TODO: Implement me */ + DbgPrint("ABI[%s] loads %s\n", abi, "/usr/lib/liblivebox-cpp.so"); + return strdup("/usr/lib/liblivebox-cpp.so"); +} + +static inline char *old_style_path(const char *pkgname) +{ + char *path; + int path_len; + int ret; + + path_len = (strlen(pkgname) * 2) + strlen(MODULE_PATH); + path = malloc(path_len); + if (!path) { + ErrPrint("Memory: %s\n", strerror(errno)); + return NULL; + } + + ret = snprintf(path, path_len, MODULE_PATH, pkgname, pkgname); + if (ret < 0) { + ErrPrint("Fault: %s\n", strerror(errno)); + free(path); + return NULL; + } + + DbgPrint("Fallback to old style libexec path (%s)\n", path); + return path; +} + +static inline char *so_path_alloc(const char *pkgname) +{ + char *lb_pkgname; + char *path; + + lb_pkgname = livebox_service_pkgname(pkgname); + if (!lb_pkgname) { + path = old_style_path(pkgname); + } else { + path = livebox_service_libexec(lb_pkgname); + free(lb_pkgname); + } + + DbgPrint("so path: %s\n", path); + return path; +} + +static void delete_livebox(struct so_item *item) +{ + if (item->adaptor.finalize) { + int ret; + fault_mark_call(item->pkgname, "finalize", __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + ret = item->adaptor.finalize(item->pkgname); + fault_unmark_call(item->pkgname, "finalize", __func__, USE_ALARM); + + ErrPrint("Package %s, finalize returns %d\n", item->pkgname, ret); + } else if (item->livebox.finalize) { + int ret; + fault_mark_call(item->pkgname, "finalize", __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + ret = item->livebox.finalize(); + fault_unmark_call(item->pkgname, "finalize", __func__, USE_ALARM); + + ErrPrint("Package %s, finalize returns %d\n", item->pkgname, ret); + } + + heap_monitor_del_target(item->so_fname); + dlclose(item->handle); + free(item->so_fname); + free(item->pkgname); + free(item); +} + +static struct so_item *new_adaptor(const char *pkgname, const char *abi) +{ + struct so_item *item; + + item = calloc(1, sizeof(*item)); + if (!item) { + ErrPrint("Memory: %s\n", strerror(errno)); + return NULL; + } + + item->pkgname = strdup(pkgname); + if (!item->pkgname) { + ErrPrint("Memory: %s\n", strerror(errno)); + free(item); + return NULL; + } + + /*! \TODO: + * item->timeout + */ + + /*! \TODO + * item->has_livbox_script + */ + + item->inst_list = NULL; + + item->so_fname = so_adaptor_alloc(abi); + if (!item->so_fname) { + free(item->pkgname); + free(item); + return NULL; + } + + fault_mark_call(pkgname, __func__, __func__, USE_ALARM, DEFAULT_LOAD_TIMER); + item->handle = dlopen(item->so_fname, RTLD_LOCAL | RTLD_NOW | RTLD_DEEPBIND); + if (!item->handle) { + fault_unmark_call(pkgname, __func__, __func__, USE_ALARM); + ErrPrint("dlopen: %s - %s\n", dlerror(), item->so_fname); + free(item->so_fname); + free(item->pkgname); + free(item); + return NULL; + } + fault_unmark_call(pkgname, __func__, __func__, USE_ALARM); + + item->adaptor.create = (adaptor_create_t)dlsym(item->handle, "livebox_create"); + if (!item->adaptor.create) { + ErrPrint("symbol: livebox_create - %s\n", dlerror()); + delete_livebox(item); + return NULL; + } + + item->adaptor.destroy = (adaptor_destroy_t)dlsym(item->handle, "livebox_destroy"); + if (!item->adaptor.destroy) { + ErrPrint("symbol: livebox_destroy - %s\n", dlerror()); + delete_livebox(item); + return NULL; + } + + item->adaptor.pinup = (adaptor_pinup_t)dlsym(item->handle, "livebox_pinup"); + if (!item->adaptor.pinup) + ErrPrint("symbol: livebox_pinup - %s\n", dlerror()); + + item->adaptor.is_updated = (adaptor_is_updated_t)dlsym(item->handle, "livebox_need_to_update"); + if (!item->adaptor.is_updated) + ErrPrint("symbol: livebox_need_to_update - %s\n", dlerror()); + + item->adaptor.update_content = (adaptor_update_content_t)dlsym(item->handle, "livebox_update_content"); + if (!item->adaptor.update_content) + ErrPrint("symbol: livebox_update_content - %s\n", dlerror()); + + item->adaptor.clicked = (adaptor_clicked_t)dlsym(item->handle, "livebox_clicked"); + if (!item->adaptor.clicked) + ErrPrint("symbol: livebox_clicked - %s\n", dlerror()); + + item->adaptor.script_event = (adaptor_script_t)dlsym(item->handle, "livebox_content_event"); + if (!item->adaptor.script_event) + ErrPrint("symbol: livebox_content_event - %s\n", dlerror()); + + item->adaptor.resize = (adaptor_resize_t)dlsym(item->handle, "livebox_resize"); + if (!item->adaptor.resize) + ErrPrint("symbol: livebox_resize - %s\n", dlerror()); + + item->adaptor.create_needed = (adaptor_create_needed_t)dlsym(item->handle, "livebox_need_to_create"); + if (!item->adaptor.create_needed) + ErrPrint("symbol: livebox_need_to_create - %s\n", dlerror()); + + item->adaptor.change_group = (adaptor_change_group_t)dlsym(item->handle, "livebox_change_group"); + if (!item->adaptor.change_group) + ErrPrint("symbol: livebox_change_group - %s\n", dlerror()); + + item->adaptor.get_output_info = (adaptor_get_output_info_t)dlsym(item->handle, "livebox_get_info"); + if (!item->adaptor.get_output_info) + ErrPrint("symbol: livebox_get_info - %s\n", dlerror()); + + item->adaptor.initialize = (adaptor_initialize_t)dlsym(item->handle, "livebox_initialize"); + if (!item->adaptor.initialize) + ErrPrint("symbol: livebox_initialize - %s\n", dlerror()); + + item->adaptor.finalize = (adaptor_finalize_t)dlsym(item->handle, "livebox_finalize"); + if (!item->adaptor.finalize) + ErrPrint("symbol: livebox_finalize - %s\n", dlerror()); + + item->adaptor.need_to_destroy = (adaptor_need_to_destroy_t)dlsym(item->handle, "livebox_need_to_destroy"); + if (!item->adaptor.need_to_destroy) + ErrPrint("symbol: livebox_need_to_destroy - %s\n", dlerror()); + + item->adaptor.sys_event = (adaptor_system_event_t)dlsym(item->handle, "livebox_system_event"); + if (!item->adaptor.sys_event) + ErrPrint("symbol: lievbox_system_event - %s\n", dlerror()); + + item->adaptor.is_pinned_up = (adaptor_is_pinned_up_t)dlsym(item->handle, "livebox_is_pinned_up"); + if (!item->adaptor.is_pinned_up) + ErrPrint("symbol: livebox_is_pinned_up - %s\n", dlerror()); + + if (item->adaptor.initialize) { + int ret; + fault_mark_call(pkgname, "initialize", __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + ret = item->adaptor.initialize(pkgname); + fault_unmark_call(pkgname, "initialize", __func__, USE_ALARM); + if (ret < 0) { + ErrPrint("Failed to initialize package %s\n", pkgname); + heap_monitor_del_target(item->so_fname); + delete_livebox(item); + return NULL; + } + } + + s_info.livebox_list = eina_list_append(s_info.livebox_list, item); + return item; +} + +static struct so_item *new_livebox(const char *pkgname) +{ + struct so_item *item; + + item = calloc(1, sizeof(*item)); + if (!item) { + ErrPrint("Memory: %s\n", strerror(errno)); + return NULL; + } + + item->pkgname = strdup(pkgname); + if (!item->pkgname) { + ErrPrint("Memory: %s\n", strerror(errno)); + free(item); + return NULL; + } + + /*! \TODO: + * item->timeout + */ + + /*! \TODO + * item->has_livbox_script + */ + + item->inst_list = NULL; + + item->so_fname = so_path_alloc(pkgname); + if (!item->so_fname) { + free(item->pkgname); + free(item); + return NULL; + } + + fault_mark_call(pkgname, __func__, __func__, USE_ALARM, DEFAULT_LOAD_TIMER); + item->handle = dlopen(item->so_fname, RTLD_LOCAL | RTLD_NOW | RTLD_DEEPBIND); + if (!item->handle) { + fault_unmark_call(pkgname, __func__, __func__, USE_ALARM); + ErrPrint("dlopen: %s - %s\n", dlerror(), item->so_fname); + free(item->so_fname); + free(item->pkgname); + free(item); + return NULL; + } + fault_unmark_call(pkgname, __func__, __func__, USE_ALARM); + + item->livebox.create = (create_t)dlsym(item->handle, "livebox_create"); + if (!item->livebox.create) { + ErrPrint("symbol: livebox_create - %s\n", dlerror()); + delete_livebox(item); + return NULL; + } + + item->livebox.destroy = (destroy_t)dlsym(item->handle, "livebox_destroy"); + if (!item->livebox.destroy) { + ErrPrint("symbol: livebox_destroy - %s\n", dlerror()); + delete_livebox(item); + return NULL; + } + + item->livebox.pinup = (pinup_t)dlsym(item->handle, "livebox_pinup"); + if (!item->livebox.pinup) + ErrPrint("symbol: livebox_pinup - %s\n", dlerror()); + + item->livebox.is_updated = (is_updated_t)dlsym(item->handle, "livebox_need_to_update"); + if (!item->livebox.is_updated) + ErrPrint("symbol: livebox_need_to_update - %s\n", dlerror()); + + item->livebox.update_content = (update_content_t)dlsym(item->handle, "livebox_update_content"); + if (!item->livebox.update_content) + ErrPrint("symbol: livebox_update_content - %s\n", dlerror()); + + item->livebox.clicked = (clicked_t)dlsym(item->handle, "livebox_clicked"); + if (!item->livebox.clicked) + ErrPrint("symbol: livebox_clicked - %s\n", dlerror()); + + item->livebox.script_event = (script_t)dlsym(item->handle, "livebox_content_event"); + if (!item->livebox.script_event) + ErrPrint("symbol: livebox_content_event - %s\n", dlerror()); + + item->livebox.resize = (resize_t)dlsym(item->handle, "livebox_resize"); + if (!item->livebox.resize) + ErrPrint("symbol: livebox_resize - %s\n", dlerror()); + + item->livebox.create_needed = (create_needed_t)dlsym(item->handle, "livebox_need_to_create"); + if (!item->livebox.create_needed) + ErrPrint("symbol: livebox_need_to_create - %s\n", dlerror()); + + item->livebox.change_group = (change_group_t)dlsym(item->handle, "livebox_change_group"); + if (!item->livebox.change_group) + ErrPrint("symbol: livebox_change_group - %s\n", dlerror()); + + item->livebox.get_output_info = (get_output_info_t)dlsym(item->handle, "livebox_get_info"); + if (!item->livebox.get_output_info) + ErrPrint("symbol: livebox_get_info - %s\n", dlerror()); + + item->livebox.initialize = (initialize_t)dlsym(item->handle, "livebox_initialize"); + if (!item->livebox.initialize) + ErrPrint("symbol: livebox_initialize - %s\n", dlerror()); + + item->livebox.finalize = (finalize_t)dlsym(item->handle, "livebox_finalize"); + if (!item->livebox.finalize) + ErrPrint("symbol: livebox_finalize - %s\n", dlerror()); + + item->livebox.need_to_destroy = (need_to_destroy_t)dlsym(item->handle, "livebox_need_to_destroy"); + if (!item->livebox.need_to_destroy) + ErrPrint("symbol: livebox_need_to_destroy - %s\n", dlerror()); + + item->livebox.sys_event = (system_event_t)dlsym(item->handle, "livebox_system_event"); + if (!item->livebox.sys_event) + ErrPrint("symbol: livebox_system_event - %s\n", dlerror()); + + item->livebox.is_pinned_up = (is_pinned_up_t)dlsym(item->handle, "livebox_is_pinned_up"); + if (!item->livebox.is_pinned_up) + ErrPrint("symbol: livebox_is_pinned_up - %s\n", dlerror()); + + heap_monitor_add_target(item->so_fname); + + if (item->livebox.initialize) { + int ret; + fault_mark_call(pkgname, "initialize", __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + ret = item->livebox.initialize(pkgname); + fault_unmark_call(pkgname, "initialize", __func__, USE_ALARM); + if (ret < 0) { + ErrPrint("Failed to initialize package %s\n", pkgname); + heap_monitor_del_target(item->so_fname); + delete_livebox(item); + return NULL; + } + } + + s_info.livebox_list = eina_list_append(s_info.livebox_list, item); + return item; +} + +static inline struct instance *new_instance(const char *id, const char *content, const char *cluster, const char *category) +{ + struct instance *inst; + + inst = malloc(sizeof(*inst)); + if (!inst) { + ErrPrint("Heap: %s\n", strerror(errno)); + return NULL; + } + + inst->id = strdup(id); + if (!inst->id) { + ErrPrint("Heap: %s\n", strerror(errno)); + free(inst); + return NULL; + } + + if (content) { + inst->content = strdup(content); + if (!inst->content) { + ErrPrint("memory: %s\n", strerror(errno)); + free(inst->id); + free(inst); + return NULL; + } + } else { + inst->content = NULL; + } + + if (cluster) { + inst->cluster = strdup(cluster); + if (!inst->cluster) { + ErrPrint("memory: %s\n", strerror(errno)); + free(inst->id); + free(inst->content); + free(inst); + return NULL; + } + } else { + inst->cluster = NULL; + } + + if (category) { + inst->category = strdup(category); + if (!inst->category) { + ErrPrint("memory: %s\n", strerror(errno)); + free(inst->cluster); + free(inst->id); + free(inst->content); + free(inst); + return NULL; + } + } else { + inst->category = NULL; + } + + inst->w = 0; + inst->h = 0; + inst->priority = 0; + inst->title = NULL; + + return inst; +} + +static inline int delete_instance(struct instance *inst) +{ + free(inst->cluster); + free(inst->category); + free(inst->id); + free(inst->content); + free(inst->title); + free(inst); + return 0; +} + +static inline struct instance *find_instance(struct so_item *item, const char *id) +{ + struct instance *inst; + Eina_List *l; + + EINA_LIST_FOREACH(item->inst_list, l, inst) { + if (!strcmp(inst->id, id)) + return inst; + } + + return NULL; +} + +HAPI struct instance *so_find_instance(const char *pkgname, const char *id) +{ + struct so_item *item; + + item = find_livebox(pkgname); + if (!item) + return NULL; + + return find_instance(item, id); +} + +HAPI int so_create(const char *pkgname, const char *id, const char *content_info, int timeout, int has_livebox_script, const char *cluster, const char *category, const char *abi, struct instance **out) +{ + struct so_item *item; + struct instance *inst; + int ret; + + item = find_livebox(pkgname); + if (item) { + inst = find_instance(item, id); + if (inst) { + ErrPrint("Instance: %s - %s is already exists\n", pkgname, id); + return -EEXIST; + } + } else { + if (!strcasecmp(abi, "c")) + item = new_livebox(pkgname); + else + item = new_adaptor(pkgname, abi); + if (!item) + return -EFAULT; + } + + inst = new_instance(id, content_info, cluster, category); + if (!inst) { + if (!item->inst_list) + delete_livebox(item); + + return -EFAULT; + } + + item->inst_list = eina_list_append(item->inst_list, inst); + item->has_livebox_script = has_livebox_script; + item->timeout = timeout; + + fault_mark_call(pkgname, id, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + + if (item->adaptor.create) + ret = item->adaptor.create(pkgname, util_uri_to_path(id), content_info, cluster, category); + else if (item->livebox.create) + ret = item->livebox.create(util_uri_to_path(id), content_info, cluster, category); + else /*! \NOTE: This is not possible, but for the exceptional handling */ + ret = -ENOSYS; + + fault_unmark_call(pkgname, id, __func__, USE_ALARM); + + if (ret < 0) { + item->inst_list = eina_list_remove(item->inst_list, inst); + delete_instance(inst); + + if (!item->inst_list) { + /* There is no instances, unload this livebox */ + s_info.livebox_list = eina_list_remove(s_info.livebox_list, item); + delete_livebox(item); + } + return ret; + } + + inst->item = item; + *out = inst; + return ret; +} + +HAPI int so_destroy(struct instance *inst) +{ + struct so_item *item; + int ret; + + item = inst->item; + if (!item) + return -EINVAL; + + fault_mark_call(item->pkgname, inst->id, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + + if (item->adaptor.destroy) + ret = item->adaptor.destroy(item->pkgname, util_uri_to_path(inst->id)); + else if (item->livebox.destroy) + ret = item->livebox.destroy(util_uri_to_path(inst->id)); + else + ret = -ENOSYS; + + fault_unmark_call(item->pkgname, inst->id, __func__, USE_ALARM); + + item->inst_list = eina_list_remove(item->inst_list, inst); + delete_instance(inst); + + if (!item->inst_list) { + s_info.livebox_list = eina_list_remove(s_info.livebox_list, item); + delete_livebox(item); + } + + return ret; +} + +HAPI char *so_pinup(struct instance *inst, int pinup) +{ + struct so_item *item; + char *ret; + + item = inst->item; + if (!item) + return NULL; + + fault_mark_call(item->pkgname, inst->id, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + if (item->adaptor.pinup) + ret = item->adaptor.pinup(item->pkgname, util_uri_to_path(inst->id), pinup); + else if (item->livebox.pinup) + ret = item->livebox.pinup(util_uri_to_path(inst->id), pinup); + else + ret = NULL; + fault_unmark_call(item->pkgname, inst->id, __func__, USE_ALARM); + return ret; +} + +HAPI int so_is_pinned_up(struct instance *inst) +{ + struct so_item *item; + int ret; + + item = inst->item; + if (!item) + return -EINVAL; + + fault_mark_call(item->pkgname, inst->id, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + if (item->adaptor.is_pinned_up) + ret = item->adaptor.is_pinned_up(item->pkgname, util_uri_to_path(inst->id)); + else if (item->livebox.is_pinned_up) + ret = item->livebox.is_pinned_up(util_uri_to_path(inst->id)); + else + ret = -ENOSYS; + fault_unmark_call(item->pkgname, inst->id, __func__, USE_ALARM); + return ret; +} + +HAPI int so_is_updated(struct instance *inst) +{ + struct so_item *item; + int ret; + + item = inst->item; + if (!item) + return -EINVAL; + + fault_mark_call(item->pkgname, inst->id, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + + if (item->adaptor.is_updated) + ret = item->adaptor.is_updated(item->pkgname, util_uri_to_path(inst->id)); + else if (item->livebox.is_updated) + ret = item->livebox.is_updated(util_uri_to_path(inst->id)); + else + ret = -ENOSYS; + + fault_unmark_call(item->pkgname, inst->id, __func__, USE_ALARM); + + return ret; +} + +HAPI int so_need_to_destroy(struct instance *inst) +{ + struct so_item *item; + int ret; + + item = inst->item; + if (!item) + return -EINVAL; + + fault_mark_call(item->pkgname, inst->id, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + + if (item->adaptor.need_to_destroy) + ret = item->adaptor.need_to_destroy(item->pkgname, util_uri_to_path(inst->id)); + else if (item->livebox.need_to_destroy) + ret = item->livebox.need_to_destroy(util_uri_to_path(inst->id)); + else + ret = -ENOSYS; + + fault_unmark_call(item->pkgname, inst->id, __func__, USE_ALARM); + + return ret; +} + +HAPI int so_update(struct instance *inst) +{ + struct so_item *item; + int ret; + + item = inst->item; + if (!item) + return -EINVAL; + + fault_mark_call(item->pkgname, inst->id, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + + if (item->adaptor.update_content) + ret = item->adaptor.update_content(item->pkgname, util_uri_to_path(inst->id)); + else if (item->livebox.update_content) + ret = item->livebox.update_content(util_uri_to_path(inst->id)); + else + ret = -ENOSYS; + + fault_unmark_call(item->pkgname, inst->id, __func__, USE_ALARM); + return ret; +} + +HAPI int so_clicked(struct instance *inst, const char *event, double timestamp, double x, double y) +{ + struct so_item *item; + int ret; + + item = inst->item; + if (!item) + return -EINVAL; + + fault_mark_call(item->pkgname, inst->id, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + + if (item->adaptor.clicked) + ret = item->adaptor.clicked(item->pkgname, util_uri_to_path(inst->id), event, timestamp, x, y); + else if (item->livebox.clicked) + ret = item->livebox.clicked(util_uri_to_path(inst->id), event, timestamp, x, y); + else + ret = -ENOSYS; + + fault_unmark_call(item->pkgname, inst->id, __func__, USE_ALARM); + + return ret; +} + +HAPI int so_script_event(struct instance *inst, const char *emission, const char *source, struct event_info *event_info) +{ + struct so_item *item; + int ret; + + item = inst->item; + if (!item) + return -EINVAL; + + fault_mark_call(item->pkgname, inst->id, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + + if (item->adaptor.script_event) + ret = item->adaptor.script_event(item->pkgname, util_uri_to_path(inst->id), emission, source, event_info); + else if (item->livebox.script_event) + ret = item->livebox.script_event(util_uri_to_path(inst->id), emission, source, event_info); + else + ret = -ENOSYS; + + fault_unmark_call(item->pkgname, inst->id, __func__, USE_ALARM); + + return ret; +} + +HAPI int so_resize(struct instance *inst, int w, int h) +{ + struct so_item *item; + int ret; + int type; + + item = inst->item; + if (!item) + return -EINVAL; + + type = livebox_service_size_type(w, h); + if (type == LB_SIZE_TYPE_UNKNOWN) + return -EINVAL; + + fault_mark_call(item->pkgname, inst->id, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + + if (item->adaptor.resize) + ret = item->adaptor.resize(item->pkgname, util_uri_to_path(inst->id), type); + else if (item->livebox.resize) + ret = item->livebox.resize(util_uri_to_path(inst->id), type); + else + ret = -ENOSYS; + + fault_unmark_call(item->pkgname, inst->id, __func__, USE_ALARM); + + return ret; +} + +HAPI int so_create_needed(const char *pkgname, const char *cluster, const char *category, const char *abi) +{ + struct so_item *item; + int ret; + + item = find_livebox(pkgname); + if (!item) { + if (!strcasecmp(abi, "c")) + item = new_livebox(pkgname); + else + item = new_adaptor(pkgname, abi); + if (!item) + return -EFAULT; + } + + fault_mark_call(item->pkgname, __func__, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + + if (item->adaptor.create_needed) + ret = item->adaptor.create_needed(pkgname, cluster, category); + else if (item->livebox.create_needed) + ret = item->livebox.create_needed(cluster, category); + else + ret = -ENOSYS; + + fault_unmark_call(item->pkgname, __func__, __func__, USE_ALARM); + + DbgPrint("[%s] returns %d\n", pkgname, ret); + return ret; +} + +HAPI int so_change_group(struct instance *inst, const char *cluster, const char *category) +{ + struct so_item *item; + int ret; + char *tmp_cluster; + char *tmp_category; + + item = inst->item; + if (!item) + return -EINVAL; + + tmp_cluster = strdup(cluster); + if (!tmp_cluster) + return -ENOMEM; + + tmp_category = strdup(category); + if (!tmp_category) { + free(tmp_cluster); + return -ENOMEM; + } + + fault_mark_call(item->pkgname, inst->id, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + + if (item->adaptor.change_group) + ret = item->adaptor.change_group(item->pkgname, util_uri_to_path(inst->id), cluster, category); + else if (item->livebox.change_group) + ret = item->livebox.change_group(util_uri_to_path(inst->id), cluster, category); + else + ret = -ENOSYS; + + fault_unmark_call(item->pkgname, inst->id, __func__, USE_ALARM); + if (ret >= 0) { + free(inst->cluster); + free(inst->category); + + inst->cluster = tmp_cluster; + inst->category = tmp_category; + } else { + free(tmp_cluster); + free(tmp_category); + } + + return ret; +} + +HAPI int so_get_output_info(struct instance *inst, int *w, int *h, double *priority, char **content, char **title) +{ + struct so_item *item; + int ret; + + item = inst->item; + if (!item) + return -EINVAL; + + *content = NULL; + *title = NULL; + + fault_mark_call(item->pkgname, inst->id, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + + if (item->adaptor.get_output_info) + ret = item->adaptor.get_output_info(item->pkgname, util_uri_to_path(inst->id), w, h, priority, content, title); + else if (item->livebox.get_output_info) + ret = item->livebox.get_output_info(util_uri_to_path(inst->id), w, h, priority, content, title); + else + ret = -ENOSYS; + + fault_unmark_call(item->pkgname, inst->id, __func__, USE_ALARM); + if (ret >= 0) { + inst->w = *w; + inst->h = *h; + inst->priority = *priority; + + /*! + * \todo + * Add "*content" "*title" address validation code. + * using mcheck? + */ + + if (*content) { + free(inst->content); + inst->content = *content; + } + + if (*title) { + free(inst->title); + inst->title = *title; + } + } + + return ret; +} + +HAPI int so_sys_event(struct instance *inst, int event) +{ + struct so_item *item; + int ret; + + item = inst->item; + if (!item) + return -EINVAL; + + fault_mark_call(item->pkgname, inst->id, __func__, USE_ALARM, DEFAULT_LIFE_TIMER); + if (item->adaptor.sys_event) + ret = item->adaptor.sys_event(item->pkgname, util_uri_to_path(inst->id), event); + else if (item->livebox.sys_event) + ret = item->livebox.sys_event(util_uri_to_path(inst->id), event); + else + ret = -ENOSYS; + + fault_unmark_call(item->pkgname, inst->id, __func__, USE_ALARM); + return ret; +} + +/* End of a file */ diff --git a/src/update_monitor.c b/src/update_monitor.c new file mode 100644 index 0000000..bb13c52 --- /dev/null +++ b/src/update_monitor.c @@ -0,0 +1,305 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "critical_log.h" +#include "update_monitor.h" +#include "util.h" +#include "debug.h" +#include "conf.h" + +int errno; + +struct cb_item { + char *filename; + int (*cb)(const char *filename, void *data, int over); + void *data; +}; + +static struct info { + int ifd; + int iwd; + Ecore_Fd_Handler *handler; + Eina_List *update_list; + Eina_List *delete_list; +} s_info = { + .ifd = -EINVAL, + .iwd = -EINVAL, + .handler = NULL, + .update_list = NULL, + .delete_list = NULL, +}; + +static Eina_Bool monitor_cb(void *data, Ecore_Fd_Handler *handler) +{ + int fd; + int read_size; + Eina_List *l; + Eina_List *n; + struct cb_item *item; + char *buffer; + register int i; + struct inotify_event *evt; + char *filename; + int len; + int ret; + + fd = ecore_main_fd_handler_fd_get(handler); + if (fd < 0) { + ErrPrint("Failed to get file handler\n"); + return ECORE_CALLBACK_CANCEL; + } + + if (ioctl(fd, FIONREAD, &read_size) < 0) { + ErrPrint("Failed to get q size (%s)\n", strerror(errno)); + return ECORE_CALLBACK_CANCEL; + } + + if (read_size <= 0) { + ErrPrint("Buffer is not ready!!!\n"); + return ECORE_CALLBACK_RENEW; + } + + buffer = calloc(read_size+1, sizeof(char)); + if (!buffer) { + ErrPrint("Error: %s\n", strerror(errno)); + return ECORE_CALLBACK_CANCEL; + } + + if (read(fd, buffer, read_size) != read_size) { + ErrPrint("Could not get entire events (%s)\n", strerror(errno)); + free(buffer); + return ECORE_CALLBACK_CANCEL; + } + + i = 0; + while (i < read_size) { + evt = (struct inotify_event *)(buffer + i); + i += sizeof(*evt) + evt->len; + + if (util_check_ext(evt->name, "gnp.") == 0 + && util_check_ext(evt->name, "csed.") == 0) + continue; + + len = strlen(evt->name) + strlen(IMAGE_PATH) + 1; + filename = malloc(len); + if (!filename) { + ErrPrint("Error: %s\n", strerror(errno)); + /* We met error, but keep going, + * and care the remained buffer. + */ + continue; + } + + ret = snprintf(filename, len, "%s%s", IMAGE_PATH, evt->name); + if (ret < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + /* We met error, but keep goging. + * and care the remained buffer. + */ + free(filename); + continue; + } + + if (evt->mask & (IN_DELETE | IN_MOVED_FROM)) { + EINA_LIST_FOREACH_SAFE(s_info.delete_list, l, n, item) { + if (!strcmp(filename, item->filename) && item->cb(filename, item->data, !!(evt->mask & IN_Q_OVERFLOW)) == EXIT_FAILURE) { + s_info.delete_list = eina_list_remove_list(s_info.delete_list, l); + free(item->filename); + free(item); + } + } + } else if (evt->mask & (IN_CLOSE_WRITE | IN_MOVED_TO)) { + EINA_LIST_FOREACH_SAFE(s_info.update_list, l, n, item) { + if (!strcmp(filename, item->filename) && item->cb(filename, item->data, !!(evt->mask & IN_Q_OVERFLOW)) == EXIT_FAILURE) { + s_info.update_list = eina_list_remove_list(s_info.update_list, l); + free(item->filename); + free(item); + } + } + } + + free(filename); + } + + free(buffer); + return ECORE_CALLBACK_RENEW; +} + +HAPI int update_monitor_init(void) +{ + s_info.ifd = inotify_init(); + if (s_info.ifd < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + return -EIO; + } + + if (access(IMAGE_PATH, R_OK | X_OK) != 0) { + ErrPrint("Image folder is not exists\n"); + return -EIO; + } + + s_info.iwd = inotify_add_watch(s_info.ifd, IMAGE_PATH, + IN_DELETE | IN_CLOSE_WRITE | IN_MOVED_TO | IN_MOVED_FROM); + + if (s_info.iwd < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + close(s_info.ifd); + s_info.ifd = -EINVAL; + return -EIO; + } + + s_info.handler = ecore_main_fd_handler_add(s_info.ifd, + ECORE_FD_READ, monitor_cb, NULL, NULL, NULL); + if (!s_info.handler) { + ErrPrint("Failed to add a FD handler\n"); + if (inotify_rm_watch(s_info.ifd, s_info.iwd) < 0) + ErrPrint("inotify_rm_watch: %s", strerror(errno)); + s_info.iwd = -EINVAL; + + close(s_info.ifd); + s_info.ifd = -EINVAL; + return -EFAULT; + } + + DbgPrint("Update monitor is successfully initialized\n"); + return 0; +} + +HAPI int update_monitor_fini(void) +{ + if (!s_info.handler) { + ErrPrint("Invalid fd handler\n"); + } else { + ecore_main_fd_handler_del(s_info.handler); + s_info.handler = NULL; + } + + if (s_info.ifd >= 0) { + if (inotify_rm_watch(s_info.ifd, s_info.iwd) < 0) + ErrPrint("inotify_rm_watch:%s", strerror(errno)); + + s_info.iwd = -EINVAL; + + close(s_info.ifd); + s_info.ifd = -EINVAL; + } + + return 0; +} + +HAPI int update_monitor_add_update_cb(const char *filename, + int (*cb)(const char *filename, void *data, int over), void *data) +{ + struct cb_item *item; + + item = calloc(1, sizeof(*item)); + if (!item) { + ErrPrint("calloc:%s\n", strerror(errno)); + return -ENOMEM; + } + + item->filename = strdup(filename); + if (!item->filename) { + ErrPrint("Error: %s\n", strerror(errno)); + free(item); + return -ENOMEM; + } + item->cb = cb; + item->data = data; + + s_info.update_list = eina_list_append(s_info.update_list, item); + return 0; +} + +HAPI int update_monitor_add_delete_cb(const char *filename, + int (*cb)(const char *filename, void *data, int over), void *data) +{ + struct cb_item *item; + + item = calloc(1, sizeof(*item)); + if (!item) { + ErrPrint("calloc:%s", strerror(errno)); + return -ENOMEM; + } + + item->filename = strdup(filename); + if (!item->filename) { + ErrPrint("Error: %s\n", strerror(errno)); + free(item); + return -ENOMEM; + } + + item->cb = cb; + item->data = data; + + s_info.delete_list = eina_list_append(s_info.delete_list, item); + return 0; +} + +HAPI void *update_monitor_del_update_cb(const char *filename, + int (*cb)(const char *filename, void *data, int over)) +{ + Eina_List *l; + struct cb_item *item; + void *data; + + EINA_LIST_FOREACH(s_info.update_list, l, item) { + if (item->cb == cb && !strcmp(item->filename, filename)) { + s_info.update_list = eina_list_remove_list(s_info.update_list, l); + data = item->data; + free(item->filename); + free(item); + return data; + } + } + + return NULL; +} + +HAPI void *update_monitor_del_delete_cb(const char *filename, + int (*cb)(const char *filename, void *data, int over)) +{ + Eina_List *l; + struct cb_item *item; + void *data; + + EINA_LIST_FOREACH(s_info.delete_list, l, item) { + if (item->cb == cb && !strcmp(item->filename, filename)) { + s_info.delete_list = eina_list_remove_list(s_info.delete_list, l); + data = item->data; + free(item->filename); + free(item); + return data; + } + } + + return NULL; +} + +/* End of a file */ diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..c0ea002 --- /dev/null +++ b/src/util.c @@ -0,0 +1,174 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "critical_log.h" +#include "util.h" +#include "conf.h" +#include "debug.h" + +HAPI int util_check_ext(const char *icon, const char *ext) +{ + int len; + + len = strlen(icon) - 1; + while (len >= 0 && *ext && icon[len] == *ext) { + len--; + ext++; + } + + return *ext ? 0 : 1; +} + +HAPI double util_timestamp(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f; +} + +HAPI const char *util_basename(const char *name) +{ + int length; + + length = name ? strlen(name) : 0; + if (!length) + return "."; + + while (--length > 0 && name[length] != '/'); + + return length <= 0 ? name : name + length + (name[length] == '/'); +} + +/*! + * \note + * Just trying to find the nearest module. + * It could be wrong. + */ +HAPI char *util_get_current_module(char **symbol) +{ + int *stack; + Dl_info dinfo; + const char *ptr; + char *ret; + pthread_attr_t attr; + unsigned int stack_boundary = 0; + unsigned int stack_size = 0; + register int i; + + if (!pthread_getattr_np(pthread_self(), &attr)) { + if (!pthread_attr_getstack(&attr, (void *)&stack_boundary, &stack_size)) + stack_boundary += stack_size; + pthread_attr_destroy(&attr); + } + + ret = NULL; + for (i = 0, stack = (int *)&stack; (unsigned int)stack < stack_boundary ; stack++, i++) { + if (!dladdr((void *)*stack, &dinfo)) + continue; + + ptr = util_basename(dinfo.dli_fname); + if (strncmp(ptr, "liblive-", strlen("liblive-"))) { + DbgPrint("[%d] fname[%s] symbol[%s]\n", i, dinfo.dli_fname, dinfo.dli_sname); + /* + if (!strcmp(ptr, EXEC_NAME)) + return EXEC_NAME; + */ + + continue; + } + + ret = strdup(ptr); + + if (symbol) { + if (dinfo.dli_sname) + *symbol = strdup(dinfo.dli_sname); + else + *symbol = NULL; + } + break; + } + + return ret; +} + +HAPI const char *util_uri_to_path(const char *uri) +{ + int len; + + len = strlen(SCHEMA_FILE); + if (strncasecmp(uri, SCHEMA_FILE, len)) + return NULL; + + return uri + len; +} + +static inline void compensate_timer(Ecore_Timer *timer) +{ + struct timeval tv; + struct timeval compensator; + double delay; + double pending; + + if (gettimeofday(&tv, NULL) < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + return; + } + + compensator.tv_sec = tv.tv_sec % 60; + if (compensator.tv_sec == 0) + compensator.tv_sec = 59; + + delay = 60.0f - ((double)compensator.tv_sec + ((double)tv.tv_usec / 1000000.0f)); + pending = ecore_timer_pending_get(timer); + ecore_timer_delay(timer, delay - pending); + DbgPrint("COMPENSATED: %lf\n", delay); +} + +HAPI void *util_timer_add(double interval, Eina_Bool (*cb)(void *data), void *data) +{ + Ecore_Timer *timer; + + timer = ecore_timer_add(interval, cb, data); + if (!timer) + return NULL; + + compensate_timer(timer); + return timer; +} + +HAPI void util_timer_interval_set(void *timer, double interval) +{ + ecore_timer_interval_set(timer, interval); + compensate_timer(timer); +} + +/* End of a file */ -- 2.7.4