From a1892c90c4fa58d1b7037b2a0d787c1f2842c583 Mon Sep 17 00:00:00 2001 From: Sunmin Lee Date: Fri, 7 Sep 2018 16:46:06 +0900 Subject: [PATCH] Upload initial code of update-control Change-Id: I1dcbe045faaff449b46e3f09ce79a1cf2ce0d007 Signed-off-by: Sunmin Lee --- CMakeLists.txt | 66 +++ LICENSE | 201 ++++++++ packaging/update-control.manifest | 5 + packaging/update-control.spec | 61 +++ src/common.h | 49 ++ src/http_util.c | 373 +++++++++++++++ src/http_util.h | 44 ++ src/update_control.c | 759 ++++++++++++++++++++++++++++++ update-control.pc.in | 13 + 9 files changed, 1571 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 packaging/update-control.manifest create mode 100644 packaging/update-control.spec create mode 100644 src/common.h create mode 100644 src/http_util.c create mode 100644 src/http_util.h create mode 100644 src/update_control.c create mode 100644 update-control.pc.in diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d11bdc9 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,66 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(fw_name "update-control") + +PROJECT(${fw_name}) + +SET(CMAKE_INSTALL_PREFIX /usr) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + + +SET(INC_DIR include) +INCLUDE_DIRECTORIES(${INC_DIR} src) + +SET(requires + capi-system-info + capi-appfw-app-common + capi-appfw-app-control + message-port + bundle + dlog + libcurl + glib-2.0 + gio-2.0 + alarm-service +) + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_name} REQUIRED ${requires}) +FOREACH(flag ${${fw_name}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror -fvisibility=hidden") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib") + +AUX_SOURCE_DIRECTORY(src SOURCES) +ADD_LIBRARY(${fw_name} SHARED ${SOURCES}) + +TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS} "-ldl") + +SET_TARGET_PROPERTIES(${fw_name} + PROPERTIES + VERSION ${FULLVER} + SOVERSION ${MAJORVER} + CLEAN_DIRECT_OUTPUT 1 +) + +INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR}) +INSTALL( + DIRECTORY ${INC_DIR}/ DESTINATION include/system + FILES_MATCHING + PATTERN "${INC_DIR}/*.h" +) + +SET(PC_NAME ${fw_name}) +SET(PC_REQUIRED ${pc_requires}) +SET(PC_LDFLAGS -l${fw_name}) +SET(PC_CFLAGS -I\${includedir}/system) + +CONFIGURE_FILE( + ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc.in + ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc + @ONLY +) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + 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. + + 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, + 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 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 in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) 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 + + (d) 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 Apache License to your work. + + To apply the Apache 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 Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + + 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/packaging/update-control.manifest b/packaging/update-control.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/packaging/update-control.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/update-control.spec b/packaging/update-control.spec new file mode 100644 index 0000000..8de338a --- /dev/null +++ b/packaging/update-control.spec @@ -0,0 +1,61 @@ +Name: update-control +Version: 0.1.0 +Release: 0 +License: Apache-2.0 +Summary: Update Control API +Group: System/API +Source0: %{name}-%{version}.tar.gz +Source1001: %{name}.manifest +BuildRequires: cmake +BuildRequires: pkgconfig(capi-system-info) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(capi-appfw-app-common) +BuildRequires: pkgconfig(capi-appfw-app-control) +BuildRequires: pkgconfig(libcurl) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(message-port) +BuildRequires: pkgconfig(bundle) +BuildRequires: pkgconfig(alarm-service) + +%description +An Update Control library in Tizen C API + +%package devel +Summary: A Update Control library in Core API (Development) +Group: Development/System +Requires: %{name} = %{version}-%{release} + +%description devel + + +%prep +%setup -q +cp %{SOURCE1001} . + +%build +MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` + +%cmake . -DMAJORVER=${MAJORVER} \ + -DFULLVER=%{version} + +%__make %{?jobs:-j%jobs} + +%install +%make_install + +%post +/sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%manifest %{name}.manifest +%license LICENSE +%{_libdir}/libupdate-control.so.* + +%files devel +%manifest %{name}.manifest +%{_includedir}/system/update_control.h +%{_libdir}/pkgconfig/*.pc +%{_libdir}/libupdate-control.so diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..e22b1fc --- /dev/null +++ b/src/common.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#ifndef __TIZEN_SYSTEM_UPDATE_CONTROL_COMMON_H__ +#define __TIZEN_SYSTEM_UPDATE_CONTROL_COMMON_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#undef LOG_TAG +#define LOG_TAG "CAPI_UPDATE_CONTROL" +#define _D(fmt, args...) SLOGD(fmt, ##args) +#define _E(fmt, args...) SLOGE(fmt, ##args) +#define _I(fmt, args...) SLOGI(fmt, ##args) +#define STR_EQ(X, Y) (g_strcmp0((X), (Y)) == 0) +#define STR_EMPTY(X) STR_EQ((X), "") + +#define G_FREE(p) do { if (p) { g_free(p); p = NULL; } } while (0); + +#define retm_if(expr, fmt, arg...) \ + do { if (expr) { _E(fmt, ##arg); return; } } while (0) + +#define retvm_if(expr, val, fmt, arg...) \ + do { if (expr) { _E(fmt, ##arg); return (val); } } while (0) + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_SYSTEM_UPDATE_CONTROL_COMMON_H__ */ diff --git a/src/http_util.c b/src/http_util.c new file mode 100644 index 0000000..a84f0f0 --- /dev/null +++ b/src/http_util.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 HTTPS_TEST +#define DOWNLOAD_MONITORING + +#include +#include "http_util.h" +#include "common.h" + +#ifdef DOWNLOAD_MONITORING +#include +#endif + +#define STDM_URL "https://apis.samsungiotcloud.com/v1/stdm/fota/target" + +#ifdef DOWNLOAD_MONITORING +#define GAUGE_LENGTH 30 + +static int binary_size = 0; +#endif + +static void __curl_set_response(CURL *curl, + GByteArray *response_header, + GByteArray *response_body, + char **res_header, + char **res_body, + void *user_data) +{ + CURLcode err = CURLE_OK; + + long response = 0; + + err = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); + retm_if(err != CURLE_OK, + "Failed to get info from curl handle[%s, %d]", curl_easy_strerror(err), err); + + _D("Response Code[%ld]", response); + + char *tmp_header = g_strndup((const gchar *)response_header->data, response_header->len); + char *tmp_body = g_strndup((const gchar *)response_body->data, response_body->len); + + *res_header = tmp_header; + *res_body = tmp_body; +} + +#ifdef HTTPS_TEST +static int http_util_set_ssl_opt(CURL *curl) +{ + _D("Enable SSL verification"); + + /* For Debug */ + int curl_ret_code = curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + if (CURLE_OK != curl_ret_code) { + _E("curl_easy_setopt: CURLOPT_VERBOSE failed!! curl_ret_code[%d]", curl_ret_code); + } + + curl_ret_code = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE); + if (CURLE_OK != curl_ret_code) { + _E("curl_easy_setopt: CURLOPT_SSL_VERIFYPEER failed!! curl_ret_code[%d]", curl_ret_code); + } + + curl_ret_code = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, FALSE); + if (CURLE_OK != curl_ret_code) { + _E("curl_easy_setopt: CURLOPT_SSL_VERIFYHOST failed!! curl_ret_code[%d]", curl_ret_code); + } + + return 0; +} +#endif + +static void __curl_set_request_headers(CURL *curl) +{ + struct curl_slist *header = NULL; + char *tmp_header = NULL; + + tmp_header = g_strconcat("Content-Type: ", "application/json", NULL); + header = curl_slist_append(header, tmp_header); + g_free(tmp_header); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header); +} + +static size_t __gather_data(void *downloaded_data, + size_t size, + size_t nmemb, + void *user_data) +{ + size_t total_size = size * nmemb; + g_byte_array_append((GByteArray *)user_data, (const unsigned char *) downloaded_data, total_size); + return total_size; +} + +static void __curl_set_common_option(CURL *curl, + const char *url, + GByteArray **response_header_ptr, + GByteArray **response_body_ptr) +{ + CURLcode curl_ret_code; + + _D("set URL = [%s]", url); + curl_ret_code = curl_easy_setopt(curl, CURLOPT_URL, url); + if (CURLE_OK != curl_ret_code) { + _E("curl_easy_setopt: CURLOPT_URL failed!! curl_ret_code[%d]", curl_ret_code); + } + + GByteArray *response_header_data = g_byte_array_new(); + curl_ret_code = curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, __gather_data); + if (CURLE_OK != curl_ret_code) { + _E("curl_easy_setopt: CURLOPT_HEADERFUNCTION failed!! curl_ret_code[%d]", curl_ret_code); + } + + curl_ret_code = curl_easy_setopt(curl, CURLOPT_HEADERDATA, response_header_data); + if (CURLE_OK != curl_ret_code) { + _E("curl_easy_setopt: CURLOPT_HEADERDATA failed!! curl_ret_code[%d]", curl_ret_code); + } + + GByteArray *response_body_data = g_byte_array_new(); + + curl_ret_code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, __gather_data); + if (CURLE_OK != curl_ret_code) { + _E("curl_easy_setopt: CURLOPT_WRITEFUNCTION failed!! curl_ret_code[%d]", curl_ret_code); + } + + curl_ret_code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, response_body_data); + if (CURLE_OK != curl_ret_code) { + _E("curl_easy_setopt: CURLOPT_WRITEDATA failed!! curl_ret_code[%d]", curl_ret_code); + } + + curl_ret_code = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); + if (CURLE_OK != curl_ret_code) { + _E("curl_easy_setopt: CURLOPT_NOPROGRESS failed!! curl_ret_code[%d]", curl_ret_code); + } + + *response_header_ptr = response_header_data; + *response_body_ptr = response_body_data; +} + + +#ifdef DOWNLOAD_MONITORING +static void *_print_download_progress(void *download_path) +{ + FILE *fp = NULL; + int retry = 0; + + do { + sleep(1); + + if (!fp) { + fp = fopen((char *)download_path, "r"); + if (!fp) { + retry++; + if (retry >= 3) { + _E("Failed to open %s", (char *)download_path); + _E("%s", strerror(errno)); + break; + } + continue; + } + } + + fseek(fp, 0L, SEEK_END); + int size = ftell(fp); + rewind(fp); + + if (binary_size <= 0) { + _E("Package size is not set. Can not print progress"); + return 0; + } + + double progress = ((double)size / binary_size); + if (progress <= 1) { + char bar[GAUGE_LENGTH + 3]; + + snprintf(bar, sizeof(bar), "["); + int i = 1; + for (; i <= GAUGE_LENGTH * progress; i++) + snprintf(bar + strlen(bar), sizeof(bar), "="); + for (; i <= GAUGE_LENGTH; i++) + snprintf(bar + strlen(bar), sizeof(bar), "."); + snprintf(bar + strlen(bar), sizeof(bar), "]"); + + _D("%s | %d / %d (%d %%)", + bar, size, binary_size, + (int)(progress * 100)); + } + + if (progress >= 1) { + _D("Download Finished (%d / %d)", size, binary_size); + break; + } + } while (1); + + fclose(fp); + + return 0; +} +#endif + +int http_util_check_request_to_fota(const char *uid, + const char *access_token, + const char *device_type, + const char *current_version, + char **res_header, + char **res_body) +{ + int ret = 0; + CURL *curl = NULL; + GByteArray *response_header = NULL; + GByteArray *response_body= NULL; + CURLcode err; + struct curl_slist *header = NULL; + char *tmp_header = NULL; + char *req_url = NULL; + char query[128]; + + curl = curl_easy_init(); + retvm_if(!curl, -EIO, "Failed to init curl"); + + curl_easy_setopt(curl, CURLOPT_HTTPGET, 1); + + tmp_header = g_strconcat("X-IOT-UID: ", uid, NULL); + header = curl_slist_append(header, tmp_header); + tmp_header = g_strconcat("Authorization: ", "Bearer ", access_token, NULL); + header = curl_slist_append(header, tmp_header); + g_free(tmp_header); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header); + + snprintf(query, sizeof(query), "?deviceType=%s¤tVersion=%s", device_type, current_version); + req_url = g_strconcat(STDM_URL, query, NULL); + _D("Query URL: [%s]", req_url); + __curl_set_common_option(curl, req_url, &response_header, &response_body); + +#ifdef HTTPS_TEST + http_util_set_ssl_opt(curl); +#endif + + err = curl_easy_perform(curl); + _I("curl_easy_perform(): [%s][%d]", curl_easy_strerror(err), err); + + if (err == CURLE_ABORTED_BY_CALLBACK) { + ret = -1; + goto END; + } else if (err != CURLE_OK) { + ret = -1; + goto END; + } + + __curl_set_response(curl, response_header, response_body, res_header, res_body, NULL); + + //_D("header[%s], body[%s]", *res_header, *res_body); + +END: + if (response_header) + g_byte_array_free(response_header, TRUE); + if (response_body) + g_byte_array_free(response_body, TRUE); + + curl_easy_cleanup(curl); + return ret; +} + +int http_util_download_file(const char *download_url, const char *download_path, + int package_size) +{ + retvm_if(!download_url || !download_path, -EINVAL, "Invalid parameter"); + + FILE *fp = NULL; + CURL *curl = NULL; + CURLcode err; + + curl = curl_easy_init(); + retvm_if(!curl, -EIO, "Failed to init curl"); + +#ifdef HTTPS_TEST + http_util_set_ssl_opt(curl); +#endif + +#ifdef DOWNLOAD_MONITORING + binary_size = package_size; + + pthread_t p_thread; + int thread = pthread_create(&p_thread, NULL, _print_download_progress, (void *)download_path); + if (thread < 0) + _E("Failed to create thread"); + else + _D("Register timeout fn for monitoring"); +#endif + + fp = fopen(download_path, "wb"); + + curl_easy_setopt(curl, CURLOPT_URL, download_url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); + + err = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + fclose(fp); + +#ifdef DOWNLOAD_MONITORING + int status; + pthread_join(p_thread, (void **)&status); +#endif + + if (err != CURLE_OK) { + _I("Failed to download file[%s, %d]", curl_easy_strerror(err), err); + remove(download_path); + return -EIO; + } + + return 0; +} + +int http_util_send_request(fmwup_http_e type, const char *req_url, char **res_header, char **res_body) +{ + int ret = 0; + CURL *curl = NULL; + GByteArray *response_header = NULL; + GByteArray *response_body= NULL; + CURLcode err; + + curl = curl_easy_init(); + retvm_if(!curl, -EIO, "Failed to init curl"); + + __curl_set_request_headers(curl); + + if (type == FMWUP_HTTP_GET) { + curl_easy_setopt(curl, CURLOPT_HTTPGET, 1); + } else if (type == FMWUP_HTTP_POST) { + curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1); + } else { + return -1; + } + + __curl_set_common_option(curl, (const char *)req_url, &response_header, &response_body); + + err = curl_easy_perform(curl); + _I("curl_easy_perform(): [%s][%d]", curl_easy_strerror(err), err); + + if (err == CURLE_ABORTED_BY_CALLBACK) { + ret = -1; + goto END; + } else if (err != CURLE_OK) { + ret = -1; + goto END; + } + + __curl_set_response(curl, response_header, response_body, res_header, res_body, NULL); + +END: + if (response_header) + g_byte_array_free(response_header, TRUE); + if (response_body) + g_byte_array_free(response_body, TRUE); + + curl_easy_cleanup(curl); + return ret; +} diff --git a/src/http_util.h b/src/http_util.h new file mode 100644 index 0000000..3017f5c --- /dev/null +++ b/src/http_util.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#ifndef __TIZEN_SYSTEM_UPDATE_CONTROL_HTTP_UTIL_H__ +#define __TIZEN_SYSTEM_UPDATE_CONTROL_HTTP_UTIL_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef enum { + FMWUP_HTTP_GET = 0, + FMWUP_HTTP_POST, + FMWUP_HTTP_PUT, + FMWUP_HTTP_DELETE +} fmwup_http_e; + +int http_util_check_request_to_fota(const char *uid, const char *access_token, + const char *device_type, const char *current_version, + char **res_header, char **res_body); +int http_util_download_file(const char *download_url, const char *download_path, + int package_size); +int http_util_send_request(fmwup_http_e type, const char *req_url, + char **res_header, char **res_body); + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_SYSTEM_UPDATE_CONTROL_HTTP_UTIL_H__ */ diff --git a/src/update_control.c b/src/update_control.c new file mode 100644 index 0000000..5690d46 --- /dev/null +++ b/src/update_control.c @@ -0,0 +1,759 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 DEFAULT_PLUGIN +#define SET_POLLING + +#ifdef DEFAULT_PLUGIN +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "http_util.h" +#endif + +#include + +#ifndef API +#define API __attribute__ ((visibility("default"))) +#endif + +#ifdef DEFAULT_PLUGIN + +/* IPC with Smartthings-thing for ST cloud account info */ +#define ST_APP_THING_SERVICE_APP_ID "org.tizen.smartthings-thing" +#define ST_APP_OPERATION_UPDATE_AGENT "http://tizen.org/appcontrol/operation/update_agent" +#define ST_SVC_KEY_COMMAND "command" +#define ST_SVC_CMD_GET_ACCOUNT_INFO "get_account_info" + +#define ST_SVC_KEY_COMMAND "command" +#define ST_SVC_KEY_ACCESS_TOKEN "access_token" +#define ST_SVC_KEY_USER_ID "user_id" +#define ST_SVC_EVT_SET_ACCOUNT_INFO "evt_set_account_info" +#define ST_UPDATE_AGENT_APP_MSG_PORT_NAME_SUFFIX ".update_agent" + +/* Update dbus */ +#define UPDATE_BUS_NAME "org.tizen.system.update" +#define UPDATE_OBJECT_PATH "/Org/Tizen/System/Update" +#define UPDATE_INTERFACE_NAME UPDATE_BUS_NAME".Update" +#define UPDATE_METHOD "do_update" + +#define FIRMWARE_FILE_NAME "delta.tar.gz" + +static struct _cloud_account { + const char *access_token; + const char *user_id; +} cloud_account; + +static struct _update_info { + char *new_version; + char *package_uri; + int updatable; + int package_size; +} *update_info; + +static bool package_downloaded = false; + +static bool initialized = false; +static int msg_port_id = -1; +static alarm_id_t reserved_update_alarm_id = -1; +#ifdef SET_POLLING +static alarm_id_t polling_alarm_id = -1; +#endif // SET_POLLING + +#endif // DEFAULT_PLUGIN + +#ifdef DEFAULT_PLUGIN +static void _message_port_cb(int local_port_id, + const char *remote_app_id, + const char *remote_port, + bool trusted_remote_port, + bundle *message, + void *user_data) +{ + _D("message port callback called"); + + char *cmd = NULL; + char *access_token = NULL; + char *user_id = NULL; + + bundle_get_str(message, ST_SVC_KEY_COMMAND, &cmd); + + if (STR_EQ(cmd, ST_SVC_EVT_SET_ACCOUNT_INFO)) { + bundle_get_str(message, ST_SVC_KEY_ACCESS_TOKEN, &access_token); + bundle_get_str(message, ST_SVC_KEY_USER_ID, &user_id); + _D("Access Token: [%s], User ID: [%s]", access_token, user_id); + if (access_token && !STR_EMPTY(access_token)) + cloud_account.access_token = strdup(access_token); + if (user_id && !STR_EMPTY(user_id)) + cloud_account.user_id = strdup(user_id); + } else { + _D("No matching command"); + } +} + +static void register_account_info_message_port(void) +{ + _D("_register_trusted_message_port() called"); + + char *app_id = NULL; + char port_name[128]; + + app_get_id(&app_id); + snprintf(port_name, sizeof(port_name), "%s%s", app_id, + ST_UPDATE_AGENT_APP_MSG_PORT_NAME_SUFFIX); + free(app_id); + + msg_port_id = message_port_register_trusted_local_port(port_name, _message_port_cb, NULL); + if (msg_port_id < 0) + _E("Port register error: %d", msg_port_id); +} + +static void request_cloud_accout(void) +{ + _D("Request cloud account info"); + + app_control_h app_control = NULL; + int ret = 0; + + ret = app_control_create(&app_control); + if (ret != APP_CONTROL_ERROR_NONE) { + _E("app_control_create failed [%d]", ret); + return; + } + + app_control_set_operation(app_control, ST_APP_OPERATION_UPDATE_AGENT); + app_control_set_app_id(app_control, ST_APP_THING_SERVICE_APP_ID); + app_control_add_extra_data(app_control, ST_SVC_KEY_COMMAND, ST_SVC_CMD_GET_ACCOUNT_INFO); + + ret = app_control_send_launch_request(app_control, NULL, NULL); + if (ret != APP_CONTROL_ERROR_NONE) + _E("app_control_send_launch_request failed [%d]", ret); + + app_control_destroy(app_control); +} + +static int _parse_and_set_firmware_info(char *json) +{ + char *token; + char *key, *value; + + retvm_if(!json || *json != '{', false, "Invalid json format"); + + token = strtok(json, "\""); + while ((token = strtok(NULL, ",\"")) != NULL) { + if (*token == '}') + break; + key = strdup(token); + token = strtok(NULL, ",\""); + retvm_if(*token != ':', false, "Invalid json format"); + if (strlen(token) == 1) { + token = strtok(NULL, "\""); + if (*token == ',' || *token == '}') + *token = 0; + } else { + token++; + } + value = strdup(token); + + _D("key: [%s], value: [%s]", key, value); + + /* [TODO] Version check logic */ + if (STR_EQ(key, "version")) { + /* Not Server role? */ + if (STR_EMPTY(value)) + system_info_get_platform_string("http://tizen.org/system/build.release", + &value); + if (update_info->new_version) + free(update_info->new_version); + update_info->new_version = strdup(value); + } else if (STR_EQ(key, "binaryUrl")) { + if (update_info->package_uri) + free(update_info->package_uri); + update_info->package_uri = strdup(value); + } + else if (STR_EQ(key, "binarySize")) { + update_info->package_size = atoi(value); + } + + free(key); + free(value); + } + + return 0; +} + +static bool __check_new_version(const char *current, const char* new) +{ + retvm_if(!current || !new, false, "Invalid parameter"); + retvm_if(STR_EMPTY(current) || STR_EMPTY(new), false, + "Invalid firmware version[%s, %s]", current, new); + + _D("current version[%s], new version[%s]", current, new); + + /* + * Version policy + * - Default version format: YYYYMMDD.N + * - The later date and bigger following number mean the new one + */ + + return (strncmp(current, new, strlen(current)) < 0); +} + +static int __parse_secure_url(char *json, char **url_value) +{ + char *ret; + + retvm_if(!json && *json != '{' && *(json + 1) != '\"', false, "Invalid json format"); + + ret = strtok(json, "{\""); + retvm_if(!ret && !STR_EQ(ret, "url"), -1, "Invalid json(url)"); + + ret = strtok(NULL, "\""); + retvm_if(!ret && !STR_EQ(ret, ":"), -1, "Invalid json(:)"); + + ret = strtok(NULL, "\""); + retvm_if(!ret, -1, "Invalid json(end)"); + + *url_value = g_strdup(ret); + + return 0; +} + +static char *__get_download_url(const char *uri) +{ + int ret = 0; + char *header = NULL; + char *body = NULL; + char *download_url = NULL; + + ret = http_util_send_request(FMWUP_HTTP_GET, uri, &header, &body); + retvm_if(ret < 0, NULL, "Failed to get info including download uri[%d]", ret); + + _D("header[%s], body[%s]", header, body); + + /* Parsing URL */ + /* {"url":"https://iotm-dev-fota.s3-a...} */ + ret = __parse_secure_url(body, &download_url); + retvm_if(ret < 0, NULL, "Failed to parse download url from body[%d]", ret); + + G_FREE(header); + G_FREE(body); + + return download_url; +} + +static int send_update_signal(char *package_path) +{ + GDBusConnection *conn; + GVariant *parameters = NULL; + GVariant *reply = NULL; + GError *error = NULL; + int ret = -1; + + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + if (error) { + _E("Failed to get dbus: %s", error->message); + g_error_free(error); + return -1; + } + + parameters = g_variant_new("(s)", package_path); + + reply = g_dbus_connection_call_sync(conn, + UPDATE_BUS_NAME, + UPDATE_OBJECT_PATH, + UPDATE_INTERFACE_NAME, + UPDATE_METHOD, + parameters, + G_VARIANT_TYPE("(i)"), + G_DBUS_CALL_FLAGS_NONE, + 120000, + NULL, + &error); + if (error) { + _E("Failed to get reply: %s", error->message); + g_error_free(error); + goto exit; + } + + g_variant_get(reply, "(i)", &ret); + _I("Update signal was sent: (%d)", ret); + +exit: + if (reply) + g_variant_unref(reply); + if (parameters) + g_variant_unref(parameters); + + return ret; +} + +static int reservation_alarm_cb(alarm_id_t alarm_id, void *data) +{ + int ret; + _I("Update alarm: reserved update is triggered"); + + ret = update_control_check_new_version(); + if (ret < 0) { + _E("Failed to check new version: %d", ret); + return -1; + } + + if (!update_info->updatable) + return 0; + + _I("New version found. Do update"); + + ret = update_control_download_package(); + if (ret < 0) { + _E("Failed to download package: %d", ret); + return -1; + } + + ret = update_control_do_update(); + if (ret < 0) { + _E("Failed to update: %d", ret); + return -1; + } + + return 0; +} + +static void init_update_alarm(void) +{ + int ret; + + ret = alarmmgr_init("update_reservation"); + if (ret < 0) { + _E("alarmmgr_init failed [%d]", ret); + return; + } + + ret = alarmmgr_set_cb(reservation_alarm_cb, NULL); + if (ret < 0) { + _E("alarmmgr_set_cb failed [%d]", ret); + return; + } + +} + +#ifdef SET_POLLING +static int set_polling_alarm(void) +{ + int ret, week_flag; + time_t cur_time; + struct tm *polling_time; + alarm_date_t alarm_time; + alarm_entry_t *alarm_info = NULL; + + alarm_info = alarmmgr_create_alarm(); + if (alarm_info == NULL) { + _E("alarmmgr_create_alarm failed"); + return -1; + } + + cur_time = time(NULL); + polling_time = localtime(&cur_time); + + /* Polling period: every AM 3:00 */ + polling_time->tm_hour = 3; + polling_time->tm_min = 0; + polling_time->tm_sec = 0; + + week_flag = ALARM_WDAY_SUNDAY | ALARM_WDAY_MONDAY | + ALARM_WDAY_TUESDAY | ALARM_WDAY_WEDNESDAY | + ALARM_WDAY_THURSDAY | ALARM_WDAY_FRIDAY | + ALARM_WDAY_SATURDAY; + + alarm_time.year = polling_time->tm_year + 1900; + alarm_time.month = polling_time->tm_mon + 1; + alarm_time.day = polling_time->tm_mday; + alarm_time.hour = polling_time->tm_hour; + alarm_time.min = polling_time->tm_min; + alarm_time.sec = polling_time->tm_sec; + + ret = alarmmgr_set_time(alarm_info, alarm_time); + if (ret != ALARMMGR_RESULT_SUCCESS) { + _E("alarmmgr_set_time failed [%d]", ret); + ret = -1; + goto out; + } + _D("Polling alarm is set at every %d:%d", + polling_time->tm_hour, polling_time->tm_min); + + ret = alarmmgr_set_repeat_mode(alarm_info, ALARM_REPEAT_MODE_WEEKLY, week_flag); + if (ret != ALARMMGR_RESULT_SUCCESS) { + _E("alarmmgr_set_repeat_mode failed [%d]", ret); + goto out; + } + + ret = alarmmgr_add_alarm_with_localtime(alarm_info, NULL, &polling_alarm_id); + if (ret != ALARMMGR_RESULT_SUCCESS) { + _E("alarmmgr_add_alarm_with_localtime failed [%d]", ret); + ret = -1; + goto out; + } + _D("alarm_id [%d]", polling_alarm_id); + +out: + if (alarm_info) + alarmmgr_free_alarm(alarm_info); + + return ret; +} +#endif // SET_POLLING + +#endif // DEFAULT_PLUGIN + +API int update_control_initialize(void) +{ +#ifdef DEFAULT_PLUGIN + + if (initialized) { + _D("Already initialized"); + return UPDATE_CONTROL_ERROR_NONE; + } + + update_info = (struct _update_info *)malloc(sizeof(*update_info)); + update_info->new_version = NULL; + update_info->package_uri = NULL; + update_info->package_size = 0; + update_info->updatable = 0; + + register_account_info_message_port(); + request_cloud_accout(); + + init_update_alarm(); + +#ifdef SET_POLLING + set_polling_alarm(); +#endif // SET_POLLING + + initialized = true; + + return UPDATE_CONTROL_ERROR_NONE; +#endif // DEFAULT_PLUGIN +} + + +API int update_control_deinitialize(void) +{ +#ifdef DEFAULT_PLUGIN + int ret = 0; + + if (!initialized) { + _D("Already deinitialized"); + return UPDATE_CONTROL_ERROR_NONE; + } + + if (update_info->new_version) + free(update_info->new_version); + if (update_info->package_uri) + free(update_info->package_uri); + free(update_info); + + if ((ret = message_port_unregister_trusted_local_port(msg_port_id)) < 0) { + _E("Failed to message_port_unregister_trusted_local_port: %d", ret); + } + + if (reserved_update_alarm_id != -1) { + if ((ret = alarmmgr_remove_alarm(reserved_update_alarm_id)) < 0) { + _E("Failed to alarmmgr_remove_alarm: %d", ret); + } + reserved_update_alarm_id = -1; + } + +#ifdef SET_POLLING + if (polling_alarm_id != -1) { + if ((ret = alarmmgr_remove_alarm(polling_alarm_id)) < 0) { + _E("Failed to alarmmgr_remove_alarm: %d", ret); + } + polling_alarm_id = -1; + } +#endif // SET_POLLING + + initialized = false; + + return UPDATE_CONTROL_ERROR_NONE; +#endif // DEFAULT_PLUGIN +} + + +API int update_control_check_new_version(void) +{ +#ifdef DEFAULT_PLUGIN + int ret; + char *device_type = NULL; + char *version = NULL; + char *res_header = NULL; + char *res_body = NULL; + + _D("FN CALLED>>>>>>>>>>>>>>>>>>"); + + retvm_if(!update_info, UPDATE_CONTROL_ERROR_SYSTEM_ERROR, + "update controller not initialized"); + update_info->updatable = 0; + + ret = system_info_get_platform_string("http://tizen.org/system/model_name", + &device_type); + if (ret != SYSTEM_INFO_ERROR_NONE) { + _E("Failed to get model_name [%d]", ret); + return UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + } + ret = system_info_get_platform_string("http://tizen.org/system/build.release", + &version); + if (ret != SYSTEM_INFO_ERROR_NONE) { + _E("Failed to get build.release [%d]", ret); + return UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + } + _D("Device info: Device Type [%s], Version [%s]", device_type, version); + + if (!cloud_account.access_token || STR_EMPTY(cloud_account.access_token) + || !cloud_account.user_id || STR_EMPTY(cloud_account.user_id)) { + _D("The cloud account info is not set so request it. Try again later"); + request_cloud_accout(); + /* Wait for response from smartthings-thing */ + return UPDATE_CONTROL_ERROR_CONNECTION_REFUSED; + } else { + _D("The cloud account is not empty: token = [%s], id = [%s]", + cloud_account.access_token, cloud_account.user_id); + } + + http_util_check_request_to_fota(cloud_account.user_id, + cloud_account.access_token, device_type, version, + &res_header, &res_body); + if (!res_body || STR_EMPTY(res_body)) { + _E("No response for check request."); + return UPDATE_CONTROL_ERROR_CONNECTION_REFUSED; + } + _parse_and_set_firmware_info(res_body); + + if (__check_new_version(version, update_info->new_version)) { + _D("New version available. Download and update the firmware"); + update_info->updatable = 1; + } else { + _D("Already latest version: %s", version); + } + + return UPDATE_CONTROL_ERROR_NONE; +#endif // DEFAULT_PLUGIN +} + +API int update_control_download_package(void) +{ + _D("FN CALLED>>>>>>>>>>>>>>>>>>"); + +#ifdef DEFAULT_PLUGIN + int ret = 0; + char *download_url = NULL; + char *download_path = NULL; + + /* Check new version should be preceded */ + if (!update_info->package_uri || STR_EMPTY(update_info->package_uri)) { + _E("The package uri is empty. Check new version first"); + return UPDATE_CONTROL_ERROR_INVALID_URI; + } + + /* Downloading state */ + _D("Download package from [%s]", update_info->package_uri); + + download_url = __get_download_url(update_info->package_uri); + download_path = g_strconcat(app_get_data_path(), FIRMWARE_FILE_NAME, NULL); + + retvm_if(!download_url, UPDATE_CONTROL_ERROR_SYSTEM_ERROR, + "Failed to get download url"); + retvm_if(!download_path, UPDATE_CONTROL_ERROR_SYSTEM_ERROR, + "Failed to compose download path"); + + _I("Download url[%s] download path[%s]", download_url, download_path); + + ret = http_util_download_file((const char *)download_url, (const char *)download_path, + update_info->package_size); + retvm_if(ret < 0, UPDATE_CONTROL_ERROR_CONNECTION_REFUSED, + "Failed to download firmware[%d]", ret); + + G_FREE(download_url); + G_FREE(download_path); + + package_downloaded = true; + + return UPDATE_CONTROL_ERROR_NONE; +#endif // DEFAULT_PLUGIN +} + +API int update_control_do_update(void) +{ + _D("FN CALLED>>>>>>>>>>>>>>>>>>"); +#ifdef DEFAULT_PLUGIN + char *path = NULL; + + if (!package_downloaded) { + _E("Update package does not exist. Download it first"); + return UPDATE_CONTROL_ERROR_INVALID_PACKAGE; + } + + /* TODO: Check privilege */ + + _D("Firmware Updating..."); + + path = g_strconcat(app_get_data_path(), FIRMWARE_FILE_NAME, NULL); + retvm_if(!path, UPDATE_CONTROL_ERROR_SYSTEM_ERROR, + "Invalid parameter"); + + /* DBus activation */ + send_update_signal(path); + + /* Wait for update reboot */ + sleep(180); + + /* Should be unreachable */ + _E("Update reboot timed out"); + + return UPDATE_CONTROL_ERROR_TIMED_OUT; +#endif // DEFAULT_PLUGIN +} + +API int update_control_make_reservation(struct tm *reservation_time) +{ +#ifdef DEFAULT_PLUGIN + int ret; + alarm_date_t alarm_time; + alarm_entry_t *alarm_info = NULL; + + retvm_if(!reservation_time, UPDATE_CONTROL_ERROR_INVALID_PARAMETER, + "reservation_time is NULL"); + + alarm_info = alarmmgr_create_alarm(); + if (alarm_info == NULL) { + _E("alarmmgr_create_alarm failed"); + return UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + } + + alarm_time.year = reservation_time->tm_year + 1900; + alarm_time.month = reservation_time->tm_mon + 1; + alarm_time.day = reservation_time->tm_mday; + alarm_time.hour = reservation_time->tm_hour; + alarm_time.min = reservation_time->tm_min; + alarm_time.sec = reservation_time->tm_sec; + + ret = alarmmgr_set_time(alarm_info, alarm_time); + if (ret != ALARMMGR_RESULT_SUCCESS) { + _E("alarmmgr_set_time failed [%d]", ret); + ret = UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + goto out; + } + + ret = alarmmgr_set_type(alarm_info, ALARM_TYPE_VOLATILE); + if (ret != ALARMMGR_RESULT_SUCCESS) { + _E("alarmmgr_set_type failed [%d]", ret); + ret = UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + goto out; + } + + ret = alarmmgr_add_alarm_with_localtime(alarm_info, NULL, &reserved_update_alarm_id); + if (ret != ALARMMGR_RESULT_SUCCESS) { + _E("alarmmgr_add_alarm_with_localtime failed [%d]", ret); + ret = UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + goto out; + } + _D("alarm_id [%d]", reserved_update_alarm_id); + + ret = UPDATE_CONTROL_ERROR_NONE; +out: + if (alarm_info) + alarmmgr_free_alarm(alarm_info); + + return ret; +#endif // DEFAULT_PLUGIN +} + +API int update_control_cancel_reservation(void) +{ +#ifdef DEFAULT_PLUGIN + int ret = 0; + + if (reserved_update_alarm_id == -1) { + _I("No reserved update"); + return UPDATE_CONTROL_ERROR_NONE; + } + + ret = alarmmgr_remove_alarm(reserved_update_alarm_id); + if (ret < 0) { + _E("alarmmgr_remove_alarm failed [%d]", ret); + return UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + } + reserved_update_alarm_id = -1; + + return UPDATE_CONTROL_ERROR_NONE; +#endif // DEFAULT_PLUGIN +} + +API int update_control_get_property(update_control_property_e property, void **value) +{ +#ifdef DEFAULT_PLUGIN + _D("FN CALLED>>>>>>>>>>>>>>>>>>"); + int *int_val; + int ret = UPDATE_CONTROL_ERROR_NONE; + + switch (property) { + case UPDATE_CONTROL_PROPERTY_NEW_VERSION: + if (update_info->new_version) + *value = (void *)strdup(update_info->new_version); + else + _D("New version is NULL"); + break; + case UPDATE_CONTROL_PROPERTY_PACKAGE_URI: + if (update_info->package_uri) + *value = (void *)strdup(update_info->package_uri); + else + _D("Package URI is NULL"); + break; + case UPDATE_CONTROL_PROPERTY_PACKAGE_SIZE: + if (update_info->package_size) { + int_val = (int *)malloc(sizeof(int)); + *int_val = update_info->package_size; + *value = (void *)int_val; + free(int_val); + } else { + _D("Package size is not set"); + } + break; + case UPDATE_CONTROL_PROPERTY_RESULT: + case UPDATE_CONTROL_PROPERTY_DESCRIPTION: + _D("Not implemented for key: %d", property); + ret = UPDATE_CONTROL_ERROR_INVALID_OPERATION; + break; + case UPDATE_CONTROL_PROPERTY_UPDATE_AVAILABLE: + int_val = (int *)malloc(sizeof(int)); + *int_val = update_info->updatable; + *value = (void *)int_val; + free(int_val); + break; + default: + _E("Not supported property key: %d", property); + ret = UPDATE_CONTROL_ERROR_KEY_NOT_FOUND; + break; + } + + return ret; +#endif // DEFAULT_PLUGIN +} diff --git a/update-control.pc.in b/update-control.pc.in new file mode 100644 index 0000000..f5bb0ba --- /dev/null +++ b/update-control.pc.in @@ -0,0 +1,13 @@ +# Package Information for pkg-config + +prefix=@PREFIX@ +exec_prefix=/usr +libdir=@LIB_INSTALL_DIR@ +includedir=@INCLUDE_INSTALL_DIR@/system + +Name: @PC_NAME@ +Description: @PACKAGE_DESCRIPTION@ +Version: @VERSION@ +Requires: @PC_REQUIRED@ +Libs: -L${libdir} @PC_LDFLAGS@ +Cflags: -I${includedir} -- 2.34.1