--- /dev/null
+ 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.
--- /dev/null
+/*
+ * Copyright (c) 2024 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
+
+#include <curl/curl.h>
+#include "http_util.h"
+#include "plugin.h"
+
+#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 (curl_ret_code != CURLE_OK) {
+ _E("curl_easy_setopt: CURLOPT_VERBOSE failed!! curl_ret_code[%d]", curl_ret_code);
+ }
+
+ curl_ret_code = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
+ if (curl_ret_code != CURLE_OK) {
+ _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, 2);
+ if (curl_ret_code != CURLE_OK) {
+ _E("curl_easy_setopt: CURLOPT_SSL_VERIFYHOST failed!! curl_ret_code[%d]", curl_ret_code);
+ }
+
+ return 0;
+}
+#endif
+
+static int curl_set_authentication(CURL *curl, const char *user_id, const char *api_key)
+{
+ CURLcode curl_ret_code;
+
+ curl_ret_code = curl_easy_setopt(curl, CURLOPT_USERNAME, (char *)user_id);
+ if (curl_ret_code != CURLE_OK) {
+ _E("Failed to curl_easy_setopt with CURLOPT_USERNAME : ret_code[%d]", curl_ret_code);
+ return curl_ret_code;
+ }
+
+ curl_ret_code = curl_easy_setopt(curl, CURLOPT_PASSWORD, (char *)api_key);
+ if (curl_ret_code != CURLE_OK) {
+ _E("Failed to curl_easy_setopt with CURLOPT_PASSWORD : ret_code[%d]", curl_ret_code);
+ return curl_ret_code;
+ }
+
+ return curl_ret_code;
+}
+
+int http_util_check_remote_file_exists(const char *download_url, const char *user_id,
+ const char *api_key, int *exists)
+{
+ int ret = 0;
+ CURLcode curl_ret_code;
+
+ CURL *curl = curl_easy_init();
+ retvm_if(!curl, -EIO, "Failed to init curl");
+
+#ifdef HTTPS_TEST
+ http_util_set_ssl_opt(curl);
+#endif
+
+ if ((curl_ret_code = curl_easy_setopt(curl, CURLOPT_URL, download_url)) != CURLE_OK) {
+ _E("Failed to curl_easy_setopt with CURLOPT_URL : ret_code[%d]", curl_ret_code);
+ ret = -EIO;
+ goto cleanup;
+ }
+
+ if ((curl_ret_code = curl_easy_setopt(curl, CURLOPT_NOBODY, 1L)) != CURLE_OK) {
+ _E("Failed to curl_easy_setopt with CURLOPT_NOBODY : ret_code[%d]", curl_ret_code);
+ ret = -EIO;
+ goto cleanup;
+ }
+
+ if ((curl_ret_code = curl_easy_setopt(curl, CURLOPT_HEADER, 1L)) != CURLE_OK) {
+ _E("Failed to curl_easy_setopt with CURLOPT_HEADER : ret_code[%d]", curl_ret_code);
+ ret = -EIO;
+ goto cleanup;
+ }
+
+ if (curl_set_authentication(curl, user_id, api_key) != CURLE_OK) {
+ _E("Failed to set authenticetion credentials");
+ ret = -EIO;
+ goto cleanup;
+ }
+
+ curl_ret_code = curl_easy_perform(curl);
+ if (curl_ret_code == CURLE_OK) {
+ _I("Remote file exists");
+ *exists = 1;
+ } else if (curl_ret_code == CURLE_REMOTE_FILE_NOT_FOUND) {
+ _I("Remote file doesn't exist");
+ *exists = 0;
+ } else {
+ _E("curl_easy_perform failed with unexpected error");
+ ret = -EIO;
+ }
+
+cleanup:
+ curl_easy_cleanup(curl);
+
+ return ret;
+}
+
+int http_util_download_file(const char *download_url, const char *download_path,
+ const char *user_id, const char *api_key)
+{
+ retvm_if(!download_url || !download_path || !user_id || !api_key, -EINVAL, "Invalid parameter");
+
+ FILE *fp = NULL;
+ CURL *curl = NULL;
+ CURLcode err = CURLE_OK;
+ int ret_code = 0;
+ int curl_ret_code = CURLE_OK;
+
+ curl = curl_easy_init();
+ retvm_if(!curl, -EIO, "Failed to init curl");
+
+#ifdef HTTPS_TEST
+ http_util_set_ssl_opt(curl);
+#endif
+
+ fp = fopen(download_path, "wb");
+ if (fp == NULL) {
+ _E("Failed to open %s", download_path);
+ goto clean;
+ }
+
+ curl_ret_code = curl_easy_setopt(curl, CURLOPT_URL, download_url);
+ if (curl_ret_code != CURLE_OK) {
+ _E("Failed to curl_easy_setopt with CURLOPT_URL : ret_code[%d]", curl_ret_code);
+ goto clean;
+ }
+
+ curl_ret_code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
+ if (curl_ret_code != CURLE_OK) {
+ _E("Failed to curl_easy_setopt with CURLOPT_WRITEFUNCTION : ret_code[%d]", curl_ret_code);
+ goto clean;
+ }
+
+ curl_ret_code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
+ if (curl_ret_code != CURLE_OK) {
+ _E("Failed to curl_easy_setopt with CURLOPT_WRITEDATA : ret_code[%d]", curl_ret_code);
+ goto clean;
+ }
+
+ curl_ret_code = curl_set_authentication(curl, user_id, api_key);
+ if (curl_ret_code != CURLE_OK) {
+ _E("Failed to set authenticetion credentials");
+ goto clean;
+ }
+
+ err = curl_easy_perform(curl);
+
+clean:
+ curl_easy_cleanup(curl);
+
+ if (fp != NULL)
+ fclose(fp);
+ else
+ ret_code = -EIO;
+
+ if (curl_ret_code != CURLE_OK)
+ ret_code = -EIO;
+
+
+ if (err != CURLE_OK) {
+ _I("Failed to download file[%s, %d]", curl_easy_strerror(err), err);
+ if (remove(download_path) < 0)
+ _E("Failed to remove [%s]", download_path);
+ ret_code = -EIO;
+ }
+
+ return ret_code;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2024 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.
+ */
+#include <system/syscommon-plugin-common-interface.h>
+#include <system/syscommon-plugin-update-control.h>
+#include <system/syscommon-plugin-update-control-interface.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <alarm.h>
+#include <hal/device/hal-board.h>
+#include <system_info.h>
+
+#include "http_util.h"
+#include "plugin.h"
+
+
+#define SET_POLLING
+
+#undef EXPORT
+#define EXPORT __attribute__ ((visibility("default")))
+
+/* Assumed format for file below:
+ user_id
+ api_key
+*/
+#define BART_CREDS_FILE_PATH "/etc/bart"
+#define TIZEN_BUILD_CONFIG_PATH "/etc/tizen-build.conf"
+
+/* This dir will be used to store delta */
+#define DELTA_DIR "/opt/usr/data/fota/"
+
+#define BART_BASE_URL "https://bart.sec.samsung.net/artifactory/tizen-system-upgrade-tools-generic-local/tests/"
+
+#define STR_SIZE 250
+
+/* overkill */
+#define URL_SIZE 7 * STR_SIZE
+
+/* 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"
+
+/* For now it is the only type */
+#define DELTA_TYPE_DEFAULT "all"
+
+#ifdef DEBUG_MODE
+#define DEBUG_FLAG "/opt/etc/.debugupdate"
+#endif
+
+static struct _bart_account {
+ char api_key[STR_SIZE];
+ char user_id[STR_SIZE];
+} *bart_account;
+
+static struct _update_info {
+ char package_uri[URL_SIZE];
+ int updatable;
+} *update_info;
+
+static struct _device_info {
+ char device_type[STR_SIZE];
+ char model_name[STR_SIZE];
+ char arch[STR_SIZE];
+ char build_release_name[STR_SIZE];
+ char build_date[STR_SIZE];
+} *device_info;
+
+static alarm_id_t reserved_update_alarm_id = -1;
+static bool package_downloaded = false;
+
+#ifdef SET_POLLING
+static alarm_id_t polling_alarm_id = -1;
+#endif // SET_POLLING
+
+#ifdef DEBUG_MODE
+static bool debug_mode = false;
+#endif
+
+static int read_one_line(char *buff, FILE *fp)
+{
+ char *line = NULL;
+ size_t n = 0;
+ ssize_t read = getline(&line, &n, fp);
+ if (read < 0) {
+ _E("getline() failed");
+
+ if (line)
+ free(line);
+
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ }
+
+ strncpy(buff, line, STR_SIZE);
+ buff[strcspn(buff, "\n")] = '\0';
+
+ free(line);
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+}
+
+static int get_bart_account_creds(void)
+{
+ _I("Get BART account credentials from etc file");
+
+ FILE *fp = fopen(BART_CREDS_FILE_PATH, "r");
+ retvm_if(!fp, SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR, "Failed to open %s", BART_CREDS_FILE_PATH);
+
+ int ret;
+ ret = read_one_line(bart_account->user_id, fp);
+ if (ret < 0) {
+ _E("Failed to read user_id");
+ goto exit;
+ }
+
+ ret = read_one_line(bart_account->api_key, fp);
+ if (ret < 0) {
+ _E("Failed to read api_key");
+ goto exit;
+ }
+
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+ _D("BART credentials -> API key: [%s], User ID: [%s]",
+ bart_account->api_key, bart_account->user_id);
+
+exit:
+ fclose(fp);
+ return ret;
+}
+
+static void strncpy_guard_truncate(char *dest, char *src, size_t n)
+{
+ memcpy(dest, src, n);
+ dest[n - 1] = '\0';
+}
+
+static int get_platform_string(char *dest, const char *name)
+{
+ char *info = NULL;
+ retvm_if((system_info_get_platform_string(name, &info) != 0),
+ SYSCOMMON_UPDATE_CONTROL_ERROR_KEY_NOT_FOUND, "Failed to get platform string at key: %s", name);
+
+ strncpy_guard_truncate(dest, info, STR_SIZE);
+
+ free(info);
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+}
+
+static void change_slash_to_floor(char* str)
+{
+ size_t off = strcspn(str, "/");
+ if (off < strlen(str))
+ str[off] = '_';
+}
+
+static int get_strings_from_file(FILE *fp, off_t file_size)
+{
+ const char *arch_key = "TZ_BUILD_ARCH";
+ const char *build_date_key = "TZ_BUILD_DATE";
+ const char *build_release_name_key = "TZ_BUILD_RELEASE_NAME";
+ const int keys_count = 3;
+
+ const char *separators = " =\n\"";
+
+ char *read_buf = (char *)malloc(file_size + 1);
+ retvm_if(!read_buf, SYSCOMMON_UPDATE_CONTROL_ERROR_OUT_OF_MEMORY, "Not enough memory");
+
+ int ret = SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+ if (fread(read_buf, 1, file_size, fp) != file_size) {
+ _E("Reading config file failed");
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ goto cleanup;
+ }
+ read_buf[file_size] = '\0';
+
+ int loop_iter = 0, keys_processed = 0;
+ char *read_word = strtok(read_buf, separators);
+
+ while (read_word) {
+ if (keys_processed == keys_count) break;
+
+ loop_iter++;
+ if (loop_iter % 2 == 1) {
+ if ((strcmp(read_word, arch_key) == 0) || (strcmp(read_word, build_date_key) == 0)
+ || (strcmp(read_word, build_release_name_key) == 0)) {
+ char* key = strdup(read_word);
+ char* value = strtok(NULL, separators);
+
+ if (strcmp(key, arch_key) == 0) {
+ strncpy_guard_truncate(device_info->arch, value, STR_SIZE);
+ }
+ else if (strcmp(key, build_date_key) == 0) {
+ strncpy_guard_truncate(device_info->build_date, value, STR_SIZE);
+ }
+ else if (strcmp(key, build_release_name_key)) {
+ // There is a floor in BART so we need to add it
+ change_slash_to_floor(value);
+ strncpy_guard_truncate(device_info->build_release_name, value, STR_SIZE);
+ }
+
+ loop_iter++;
+ keys_processed++;
+ free(key);
+ }
+ }
+
+ read_word = strtok(NULL, separators);
+ }
+
+ if (keys_processed != keys_count) {
+ _E("Unexpected parsing error");
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ }
+
+cleanup:
+ if (read_buf)
+ free(read_buf);
+
+ return ret;
+}
+
+static int get_device_info(void)
+{
+ _I("Getting device into");
+
+ int ret = SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+
+ ret = get_platform_string(device_info->device_type, "http://tizen.org/system/device_type");
+ retvm_if(ret != SYSCOMMON_UPDATE_CONTROL_ERROR_NONE, ret, "Failed to get device_type");
+
+ ret = get_platform_string(device_info->model_name, "http://tizen.org/system/model_name");
+ retvm_if(ret != SYSCOMMON_UPDATE_CONTROL_ERROR_NONE, ret, "Failed to get model_name");
+
+ FILE *fp = fopen(TIZEN_BUILD_CONFIG_PATH, "r");
+ retvm_if(!fp, SYSCOMMON_UPDATE_CONTROL_ERROR_NONE, "Failed to open %s", TIZEN_BUILD_CONFIG_PATH);
+
+ fseek(fp, 0, SEEK_END);
+ off_t file_size = ftello(fp);
+ if (file_size == -1) {
+ _E("File size check error");
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ goto cleanup;
+ }
+ fseek(fp, 0 , SEEK_SET);
+
+ ret = get_strings_from_file(fp, file_size);
+ if (ret != SYSCOMMON_UPDATE_CONTROL_ERROR_NONE) {
+ _E("Failed to parse device info form config file: [%s]", TIZEN_BUILD_CONFIG_PATH);
+ goto cleanup;
+ }
+
+ _D("Device info -> device_type: %s, model_name: %s, arch: %s, build_date: %s",
+ device_info->device_type, device_info->model_name, device_info->arch, device_info->build_date);
+
+cleanup:
+ fclose(fp);
+ return ret;
+}
+
+static void build_package_url(void)
+{
+ /* URL template:
+ "BASE_URL/<build_release_name>/<device_type>--<model_name>--<delta_type>--<tz_build_arch>--<tz_build_date>@latest.tar.gz"
+ */
+ snprintf(update_info->package_uri, URL_SIZE, "%s%s/%s--%s--%s--%s--%s@latest.tar.gz",
+ BART_BASE_URL, device_info->build_release_name, device_info->device_type,
+ device_info->model_name, DELTA_TYPE_DEFAULT, device_info->arch, device_info->build_date);
+
+ _D("Package URL -> %s", update_info->package_uri);
+}
+
+/*
+ These are implemented much lower in this file.
+ Placed here for readability.
+ */
+static int update_control_check_new_version(void);
+static int update_control_download_package(void);
+static int update_control_do_update(void);
+
+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);
+ localtime_r(&cur_time, &polling_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
+
+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 void init_internal_data(void)
+{
+ bart_account->user_id[0] = '\0';
+ bart_account->api_key[0] = '\0';
+
+ update_info->package_uri[0] = '\0';
+ update_info->updatable = 0;
+
+ device_info->device_type[0] = '\0';
+ device_info->model_name[0] = '\0';
+ device_info->arch[0] = '\0';
+ device_info->build_release_name[0] = '\0';
+ device_info->build_date[0] = '\0';
+}
+
+static int update_control_initialize(void)
+{
+ _D("FN CALLED>>>>>>>>>>>>>>>>>>");
+
+#ifdef DEBUG_MODE
+ if (access(DEBUG_FLAG, F_OK) == 0) {
+ debug_mode = true;
+ _D("DEBUG_MODE: Calling test");
+
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+ }
+#endif
+
+ int ret = SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+ bart_account = NULL;
+ update_info = NULL;
+ device_info = NULL;
+
+ bart_account = (struct _bart_account *)malloc(sizeof(*bart_account));
+ if (!bart_account) {
+ _E("Failed to malloc");
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_OUT_OF_MEMORY;
+ goto exit_error;
+ }
+
+ update_info = (struct _update_info *)malloc(sizeof(*update_info));
+ if (!update_info) {
+ _E("Failed to malloc");
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_OUT_OF_MEMORY;
+ goto exit_error;
+ }
+
+ device_info = (struct _device_info *)malloc(sizeof(*device_info));
+ if (!device_info) {
+ _E("Failed to malloc");
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_OUT_OF_MEMORY;
+ goto exit_error;
+ }
+
+ init_internal_data();
+
+ ret = get_bart_account_creds();
+ if (ret != SYSCOMMON_UPDATE_CONTROL_ERROR_NONE) {
+ _E("Failed to read file with BART account credentials");
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ goto exit_error;
+ }
+
+ ret = get_device_info();
+ if (ret != SYSCOMMON_UPDATE_CONTROL_ERROR_NONE) {
+ _E("Failed to get device info");
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ goto exit_error;
+ }
+
+ build_package_url();
+
+ init_update_alarm();
+
+#ifdef SET_POLLING
+ set_polling_alarm();
+#endif // SET_POLLING
+
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+
+exit_error:
+ if (bart_account)
+ free(bart_account);
+ if (update_info)
+ free(update_info);
+ if (device_info)
+ free(device_info);
+
+ return ret;
+}
+
+static int update_control_deinitialize(void)
+{
+ _D("FN CALLED>>>>>>>>>>>>>>>>>>");
+
+#ifdef DEBUG_MODE
+ if (debug_mode) {
+ _D("DEBUG_MODE: Calling test");
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+ }
+#endif
+
+ int ret;
+
+ free(update_info);
+ free(bart_account);
+ free(device_info);
+
+ 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
+
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+}
+
+static int update_control_check_new_version(void)
+{
+ _D("FN CALLED>>>>>>>>>>>>>>>>>>");
+
+#ifdef DEBUG_MODE
+ if (debug_mode) {
+ _D("DEBUG_MODE: Calling test");
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+ }
+#endif
+
+ /* This function doesn't do much since there is no api to check with */
+
+ retvm_if(!update_info, SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR,
+ "update controller not initialized");
+ update_info->updatable = 0;
+
+ int exists;
+ retvm_if(
+ http_util_check_remote_file_exists(update_info->package_uri, bart_account->user_id,
+ bart_account->api_key, &exists) != 0,
+ SYSCOMMON_UPDATE_CONTROL_ERROR_CONNECTION_REFUSED,
+ "Failed to check if latest delta for this device exists on remote server (URL: %s)",
+ update_info->package_uri
+ );
+
+ if (exists) {
+ _D("Latest delta for this device was found on remote server");
+ update_info->updatable = 1;
+ } else {
+ _D("Latest delta for this device was not found on remote server. Device likely already updated to newest version");
+ }
+
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+}
+
+static int update_control_download_package(void)
+{
+ _D("FN CALLED>>>>>>>>>>>>>>>>>>");
+#ifdef DEBUG_MODE
+ if (debug_mode) {
+ _D("DEBUG_MODE: Calling test");
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+ }
+#endif
+
+ retvm_if(!update_info, SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR,
+ "update controller not initialized");
+
+ int ret = 0;
+ char *download_path = NULL;
+
+ if (!update_info->updatable) {
+ _D("Already updated");
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ }
+
+ _D("Download package from [%s]", update_info->package_uri);
+
+ download_path = g_strconcat(DELTA_DIR, FIRMWARE_FILE_NAME, NULL);
+
+ if (!download_path) {
+ _E("Failed to compose download path");
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ goto exit;
+ }
+
+ _I("Download url[%s] download path[%s]", update_info->package_uri, download_path);
+
+ ret = http_util_download_file((const char *)update_info->package_uri, (const char *)download_path,
+ (const char *)bart_account->user_id, (const char *)bart_account->api_key);
+ if (ret < 0) {
+ _E("Failed to download firmware[%d]", ret);
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_CONNECTION_REFUSED;
+ goto exit;
+ }
+
+ package_downloaded = true;
+
+exit:
+ G_FREE(download_path);
+
+ return ret;
+}
+
+static int update_control_do_update(void)
+{
+ _D("FN CALLED>>>>>>>>>>>>>>>>>>");
+
+#ifdef DEBUG_MODE
+ if (debug_mode) {
+ _D("DEBUG_MODE: Calling test");
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+ }
+#endif
+
+ char *path = NULL;
+
+ if (!package_downloaded) {
+ _E("Update package does not exist. Download it first");
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_INVALID_PACKAGE;
+ }
+
+ /* TODO: Check privilege */
+
+ _D("Firmware Updating...");
+
+ path = g_strconcat(DELTA_DIR, FIRMWARE_FILE_NAME, NULL);
+ if (!path) {
+ _E("Failed to g_strconcat");
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ }
+
+ /* DBus activation */
+ send_update_signal(path);
+
+ /* Wait for update reboot */
+ sleep(180);
+
+ /* Should be unreachable */
+ _E("Update reboot timed out");
+
+ G_FREE(path);
+
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_TIMED_OUT;
+}
+
+static int update_control_make_reservation(struct tm *reservation_time)
+{
+ _D("FN CALLED>>>>>>>>>>>>>>>>>>");
+
+ retvm_if(!reservation_time, SYSCOMMON_UPDATE_CONTROL_ERROR_INVALID_PARAMETER,
+ "reservation_time is NULL");
+
+#ifdef DEBUG_MODE
+ if (debug_mode) {
+ _D("DEBUG_MODE: Calling test");
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+ }
+#endif
+
+ int ret;
+ 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 SYSCOMMON_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 = SYSCOMMON_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 = SYSCOMMON_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 = SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ goto out;
+ }
+ _D("alarm_id [%d]", reserved_update_alarm_id);
+
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+out:
+ if (alarm_info)
+ alarmmgr_free_alarm(alarm_info);
+
+ return ret;
+}
+
+static int update_control_cancel_reservation(void)
+{
+ _D("FN CALLED>>>>>>>>>>>>>>>>>>");
+
+#ifdef DEBUG_MODE
+ if (debug_mode) {
+ _D("DEBUG_MODE: Calling test");
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+ }
+#endif
+
+ int ret = 0;
+
+ if (reserved_update_alarm_id == -1) {
+ _I("No reserved update");
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+ }
+ _D("Update reservation found. Cancel it");
+
+ ret = alarmmgr_remove_alarm(reserved_update_alarm_id);
+ if (ret < 0) {
+ _E("alarmmgr_remove_alarm failed [%d]", ret);
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ }
+ reserved_update_alarm_id = -1;
+
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+}
+
+static int update_control_get_property(syscommon_update_control_property_e property, void **value)
+{
+ _D("FN CALLED>>>>>>>>>>>>>>>>>>");
+
+ retvm_if(!value, SYSCOMMON_UPDATE_CONTROL_ERROR_INVALID_PARAMETER,
+ "value is NULL");
+
+#ifdef DEBUG_MODE
+ if (debug_mode)
+ switch (property) {
+ case SYSCOMMON_UPDATE_CONTROL_PROPERTY_NEW_VERSION:
+ case SYSCOMMON_UPDATE_CONTROL_PROPERTY_PACKAGE_URI:
+ case SYSCOMMON_UPDATE_CONTROL_PROPERTY_RESULT:
+ case SYSCOMMON_UPDATE_CONTROL_PROPERTY_PACKAGE_SIZE:
+ case SYSCOMMON_UPDATE_CONTROL_PROPERTY_DESCRIPTION:
+ case SYSCOMMON_UPDATE_CONTROL_PROPERTY_UPDATE_AVAILABLE:
+ _D("DEBUG_MODE: Calling test");
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+ default:
+ _E("Not supported property key: %d", property);
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_KEY_NOT_FOUND;
+ }
+#endif
+
+ int ret = SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+
+ switch (property) {
+ case SYSCOMMON_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 SYSCOMMON_UPDATE_CONTROL_PROPERTY_RESULT:
+ {
+ *value = malloc(sizeof(int));
+ if (!*value) {
+ _E("Failed to malloc");
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_OUT_OF_MEMORY;
+ }
+
+ int r = hal_device_board_get_upgrade_status(*value);
+ if (r >= 0) {
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_NONE;
+ break;
+ }
+
+ free(*value);
+
+ if (r == -ENODEV) {
+ _E("get_upgrade_status not implemented in HAL");
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_INVALID_OPERATION;
+ } else {
+ _E("Unable to get upgrade progress from HAL");
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ }
+ break;
+ }
+ case SYSCOMMON_UPDATE_CONTROL_PROPERTY_NEW_VERSION:
+ case SYSCOMMON_UPDATE_CONTROL_PROPERTY_PACKAGE_SIZE:
+ case SYSCOMMON_UPDATE_CONTROL_PROPERTY_DESCRIPTION:
+ _D("Not implemented for key: %d", property);
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_INVALID_OPERATION;
+ break;
+ case SYSCOMMON_UPDATE_CONTROL_PROPERTY_UPDATE_AVAILABLE:
+ *value = malloc(sizeof(int));
+ if (!*value) {
+ _E("Failed to malloc");
+ return SYSCOMMON_UPDATE_CONTROL_ERROR_OUT_OF_MEMORY;
+ }
+
+ *(int *)(*value) = update_info->updatable;
+ break;
+ default:
+ _E("Not supported property key: %d", property);
+ ret = SYSCOMMON_UPDATE_CONTROL_ERROR_KEY_NOT_FOUND;
+ break;
+ }
+
+ return ret;
+}
+
+static syscommon_plugin_backend_update_control_funcs plugin_funcs = {
+ .update_control_initialize = update_control_initialize,
+ .update_control_deinitialize = update_control_deinitialize,
+ .update_control_check_new_version = update_control_check_new_version,
+ .update_control_download_package = update_control_download_package,
+ .update_control_do_update = update_control_do_update,
+ .update_control_make_reservation = update_control_make_reservation,
+ .update_control_cancel_reservation = update_control_cancel_reservation,
+ .update_control_get_property = update_control_get_property,
+};
+
+static int update_control_init(void **data)
+{
+ *data = (void *)&plugin_funcs;
+
+ return 0;
+}
+
+static int update_control_exit(void *data)
+{
+ return 0;
+}
+
+syscommon_plugin_backend EXPORT system_plugin_backend_update_control_data = {
+ .name = "update-control",
+ .vendor = "Samsung",
+ .abi_version = SYSCOMMON_PLUGIN_ABI_VERSION_TIZEN_9_0,
+ .init = update_control_init,
+ .exit = update_control_exit,
+};