From: Antoni Date: Fri, 12 Apr 2024 10:08:10 +0000 (+0200) Subject: Add API functions to update-control to trigger specific update stages X-Git-Tag: accepted/tizen/unified/20240607.170524~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=cca7654978ab346a3ea310e6ff2042e15e33d57b;p=platform%2Fcore%2Fsystem%2Fupdate-control.git Add API functions to update-control to trigger specific update stages Following functions are asynchronous and have associated functions to set/unset their callbacks. * update_control_do_ro_update_async - triggers the RO update part of upgrade process (does not reboot) * update_control_do_finish_update_async - finishes update (reboots and does a few additional things) The update_control_do_update function behavior is unchanged. To use these new functions (to recieve the callbacks) the cilent needs to have a main loop. Change-Id: Iee128224f7185e8e274a999549002edfd4bf4dd1 --- diff --git a/include/update_control.h b/include/update_control.h index fee2cf2..7bbc06b 100644 --- a/include/update_control.h +++ b/include/update_control.h @@ -48,11 +48,14 @@ typedef enum { UPDATE_CONTROL_ERROR_CONNECTION_REFUSED = TIZEN_ERROR_CONNECTION_REFUSED, /**< Connection refused */ UPDATE_CONTROL_ERROR_PROTOCOL_NOT_SUPPORTED = TIZEN_ERROR_PROTOCOL_NOT_SUPPORTED, /**< Protocol not supported */ UPDATE_CONTROL_ERROR_TIMED_OUT = TIZEN_ERROR_TIMED_OUT, /**< Time out */ + UPDATE_CONTROL_ERROR_RESOURCE_BUSY = TIZEN_ERROR_RESOURCE_BUSY, /** - + + + - + + + diff --git a/packaging/update-manager.xml b/packaging/update-manager.xml index 6191c5e..417085a 100644 --- a/packaging/update-manager.xml +++ b/packaging/update-manager.xml @@ -1,7 +1,13 @@ - + + + + + + + diff --git a/src/update_control.c b/src/update_control.c index efa8790..01299d6 100644 --- a/src/update_control.c +++ b/src/update_control.c @@ -14,9 +14,13 @@ * limitations under the License. */ +#include "update_control_internal.h" + #include #include -#include "update_control_internal.h" + +#include +#include #include #include @@ -30,6 +34,113 @@ static bool initialized = false; static bool plugin_found = false; static OrgTizenUpdateManager *proxy = NULL; +typedef struct { + update_control_cb cb; + const void *data; +} _update_control_user_cb_info; + +static _update_control_user_cb_info *ro_update_user_cb_info = NULL; +static _update_control_user_cb_info *finish_update_user_cb_info = NULL; + +static void update_control_ro_update_cb_internal(GObject *source_object, GAsyncResult *res, gpointer data) +{ + _I("update_control_ro_update_cb_internal triggered"); + + if (ro_update_user_cb_info == NULL) { + _E("ro_update callback was unexpectedly unset"); + return; + } + + update_control_error_e result = UPDATE_CONTROL_ERROR_NONE; + + if (proxy == NULL) { + _E("Not initialized"); + result = UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + goto trigger_user_cb; + } + + gint status = 0; + GError *error = NULL; + + org_tizen_update_manager_call_ro_update_finish(proxy, &status, res, &error); + + if (error != NULL) { + _E("DBus method call failed: %s", error->message); + g_error_free(error); + result = UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + goto trigger_user_cb; + } + + _I("Successfully called DBus method"); + if (status < 0) { + _E("DBus method returned error code: %d", status); + result = UPDATE_CONTROL_ERROR_INVALID_OPERATION; + goto trigger_user_cb; + } + + _I("RO update completed: %d", status); + +trigger_user_cb: + ro_update_user_cb_info->cb(result, ro_update_user_cb_info->data); + + return; +} + +static void update_control_finish_update_cb_internal(GObject *source_object, GAsyncResult *res, gpointer data) +{ + _I("update_control_finish_update_cb_internal triggered"); + + if (finish_update_user_cb_info == NULL) { + _E("finish_update callback was unexpectedly unset"); + return; + } + + update_control_error_e result = UPDATE_CONTROL_ERROR_NONE; + + if (proxy == NULL) { + _E("Not initialized"); + result = UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + goto trigger_user_cb; + } + + gint status = 0; + GError *error = NULL; + + org_tizen_update_manager_call_finish_update_finish(proxy, &status, res, &error); + + if (error != NULL) { + _E("DBus method call failed: %s", error->message); + g_error_free(error); + result = UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + goto trigger_user_cb; + } + + _I("Successfully called DBus method"); + + if (status == -2) { + _I("Cannot finish update because RO update is still in progress"); + result = UPDATE_CONTROL_ERROR_RO_UPDATE_IN_PROGRESS; + goto trigger_user_cb; + } + + if (status == - 3) { + _I("Cannot finish udpate because RO update has not completed"); + result = UPDATE_CONTROL_ERROR_RO_UPDATE_NOT_COMPLETED; + goto trigger_user_cb; + } + + if (status < 0) { + _E("DBus method returned error code: %d", status); + result = UPDATE_CONTROL_ERROR_INVALID_OPERATION; + goto trigger_user_cb; + } + +trigger_user_cb: + finish_update_user_cb_info->cb(result, finish_update_user_cb_info->data); + + return; +} + API int update_control_initialize(void) { CHECK_FEATURE_SUPPORTED(DEVICE_UPDATE_FEATURE); @@ -107,6 +218,12 @@ API int update_control_deinitialize(void) _I("Failed to find initialized plugin, passed"); } + if (ro_update_user_cb_info != NULL) + free(ro_update_user_cb_info); + + if (finish_update_user_cb_info != NULL) + free(finish_update_user_cb_info); + initialized = false; plugin_found = false; return UPDATE_CONTROL_ERROR_NONE; @@ -149,16 +266,16 @@ API int update_control_do_update(void) return UPDATE_CONTROL_ERROR_SYSTEM_ERROR; } - org_tizen_update_manager_call_install_sync(proxy, &status, NULL, &error); + org_tizen_update_manager_call_ro_update_and_finish_update_sync(proxy, &status, NULL, &error); if (error != NULL) { - _E("Failed to call DBus method: %s", error->message); + _E("Failed to call DBus method: %s", error->message); g_error_free(error); return UPDATE_CONTROL_ERROR_SYSTEM_ERROR; } - _I("Successfully called DBus method call"); + _I("Successfully called DBus method call"); if (status < 0) { - _E("DBus method returned error code: %d", status); + _E("DBus method returned error code: %d", status); return UPDATE_CONTROL_ERROR_INVALID_OPERATION; } @@ -166,6 +283,134 @@ API int update_control_do_update(void) return UPDATE_CONTROL_ERROR_NONE; } +API int update_control_set_ro_update_cb(update_control_cb user_cb, const void* user_data) +{ + CHECK_FEATURE_SUPPORTED(DEVICE_UPDATE_FEATURE); + _I("udpate_control_set_ro_update_cb called"); + + if (user_cb == NULL) { + _E("user callback is null - cannot set"); + return UPDATE_CONTROL_ERROR_INVALID_PARAMETER; + } + + if (ro_update_user_cb_info != NULL) { + _I("Overwriting previously set callback"); + free(ro_update_user_cb_info); + } + + ro_update_user_cb_info = (_update_control_user_cb_info *)malloc(sizeof(*ro_update_user_cb_info)); + if (ro_update_user_cb_info == NULL) { + _E("Failed to malloc"); + return UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + } + + ro_update_user_cb_info->cb = user_cb; + ro_update_user_cb_info->data = user_data; + + return UPDATE_CONTROL_ERROR_NONE; +} + +API int update_control_unset_ro_update_cb(void) +{ + CHECK_FEATURE_SUPPORTED(DEVICE_UPDATE_FEATURE); + _I("update_control_unset_ro_update_cb called"); + + if (ro_update_user_cb_info == NULL) { + _E("Cannot unset ro_update callback - it was not set"); + return UPDATE_CONTROL_ERROR_INVALID_OPERATION; + } + + free(ro_update_user_cb_info); + ro_update_user_cb_info = NULL; + + return UPDATE_CONTROL_ERROR_NONE; +} + +API int update_control_do_ro_update_async(void) +{ + CHECK_FEATURE_SUPPORTED(DEVICE_UPDATE_FEATURE); + _I("update_control_do_ro_update_async called"); + + if (proxy == NULL) { + _E("Not initialized"); + return UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + } + + if (ro_update_user_cb_info == NULL) { + _E("Cannot launch async operation - callback was not set"); + return UPDATE_CONTROL_ERROR_INVALID_OPERATION; + } + + org_tizen_update_manager_call_ro_update(proxy, NULL, update_control_ro_update_cb_internal, NULL); + _I("Called DBus method asynchronously"); + + return UPDATE_CONTROL_ERROR_NONE; +} + +API int update_control_set_finish_update_cb(update_control_cb user_cb, const void* user_data) +{ + CHECK_FEATURE_SUPPORTED(DEVICE_UPDATE_FEATURE); + _I("udpate_control_set_finish_update_cb called"); + + if (user_cb == NULL) { + _E("user callback is null - cannot set"); + return UPDATE_CONTROL_ERROR_INVALID_PARAMETER; + } + + if (finish_update_user_cb_info != NULL) { + _I("Overwriting previously set callback"); + free(finish_update_user_cb_info); + } + + finish_update_user_cb_info = (_update_control_user_cb_info *)malloc(sizeof(*finish_update_user_cb_info)); + if (finish_update_user_cb_info == NULL) { + _E("Failed to malloc"); + return UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + } + + finish_update_user_cb_info->cb = user_cb; + finish_update_user_cb_info->data = user_data; + + return UPDATE_CONTROL_ERROR_NONE; +} + +API int update_control_unset_finish_update_cb(void) +{ + CHECK_FEATURE_SUPPORTED(DEVICE_UPDATE_FEATURE); + _I("update_control_unset_finish_update_cb called"); + + if (finish_update_user_cb_info == NULL) { + _E("Cannot unset finish_update callback - it was not set"); + return UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + } + + free(finish_update_user_cb_info); + finish_update_user_cb_info = NULL; + + return UPDATE_CONTROL_ERROR_NONE; +} + +API int update_control_do_finish_update_async(void) +{ + CHECK_FEATURE_SUPPORTED(DEVICE_UPDATE_FEATURE); + _I("update_control_do_finish_async called"); + + if (proxy == NULL) { + _E("Not initialized"); + return UPDATE_CONTROL_ERROR_SYSTEM_ERROR; + } + + if (finish_update_user_cb_info == NULL) { + _E("Cannot launch async operation - callback was not set"); + return UPDATE_CONTROL_ERROR_INVALID_OPERATION; + } + + org_tizen_update_manager_call_finish_update(proxy, NULL, update_control_finish_update_cb_internal, NULL); + _I("Called DBus method asynchronously"); + + return UPDATE_CONTROL_ERROR_NONE; +} + API int update_control_make_reservation(struct tm *reservation_time) { CHECK_FEATURE_SUPPORTED(DEVICE_UPDATE_FEATURE); diff --git a/update-manager/common/common-dbus-manager.c b/update-manager/common/common-dbus-manager.c index ea1cd8b..a422c05 100644 --- a/update-manager/common/common-dbus-manager.c +++ b/update-manager/common/common-dbus-manager.c @@ -5,6 +5,18 @@ static guint owner_id; +typedef enum { + RO_UPDATE, + FINISH, + RO_UPDATE_AND_FINISH, +} dbus_handler_action; + +typedef struct _dbus_handler_arg { + dbus_handler_action action; + OrgTizenUpdateManager *skeleton; + GDBusMethodInvocation *invocation; +} dbus_handler_arg; + static pid_t dbus_get_sender_pid(GDBusMethodInvocation *invocation) { const gchar *sender = g_dbus_method_invocation_get_sender(invocation); @@ -37,37 +49,155 @@ static pid_t dbus_get_sender_pid(GDBusMethodInvocation *invocation) return pid; } -gboolean dbus_manager_install(OrgTizenUpdateManager *skeleton, GDBusMethodInvocation *invocation, gpointer user_data) +void *dbus_call_handler(void *arg) { int ret = 0; + pid_t pid = 0; + dbus_handler_arg *handler_arg = (dbus_handler_arg *) arg; + + if (handler_arg->action != FINISH) + pid = dbus_get_sender_pid(handler_arg->invocation); + + switch (handler_arg->action) { + case RO_UPDATE: + ret = fota_installer_ro_update(pid); + if (ret < 0) + _FLOGW("Failed to perform : %d", ret); + org_tizen_update_manager_complete_ro_update(handler_arg->skeleton, handler_arg->invocation, ret); + break; + case FINISH: + ret = fota_installer_finish_update(); + if (ret < 0) + _FLOGW("Failed to perform : %d", ret); + org_tizen_update_manager_complete_finish_update(handler_arg->skeleton, handler_arg->invocation, ret); + break; + case RO_UPDATE_AND_FINISH: + ret = fota_installer_ro_update_and_finish_update(pid); + if (ret < 0) + _FLOGW("Failed to perform : %d", ret); + org_tizen_update_manager_complete_ro_update_and_finish_update(handler_arg->skeleton, handler_arg->invocation, ret); + break; + } + + free(arg); + g_thread_exit(0); +} + +gboolean dbus_manager_ro_update(OrgTizenUpdateManager *skeleton, GDBusMethodInvocation *invocation) +{ + _FLOGD("Dbus status: called"); + dbus_handler_arg *arg = (dbus_handler_arg *)malloc(sizeof(dbus_handler_arg)); + if (!arg) { + _FLOGE("Failed to malloc"); + goto fail; + } + + arg->action = RO_UPDATE; + arg->skeleton = skeleton; + arg->invocation = invocation; + + GError *error = NULL; + g_thread_try_new(NULL, (GThreadFunc)dbus_call_handler, (void *)arg, &error); + if (error != NULL) { + _FLOGE("Failed to create thread: %s", error->message); + goto fail; + } + + return TRUE; + +fail: + if (arg) + free(arg); + + org_tizen_update_manager_complete_ro_update(skeleton, invocation, -1); + return TRUE; +} + +gboolean dbus_manager_finish_update(OrgTizenUpdateManager *skeleton, GDBusMethodInvocation *invocation) +{ + _FLOGD("Dbus status: called"); + dbus_handler_arg *arg = (dbus_handler_arg *)malloc(sizeof(dbus_handler_arg)); + if (!arg) { + _FLOGE("Failed to malloc"); + goto fail; + } + + arg->action = FINISH; + arg->skeleton = skeleton; + arg->invocation = invocation; + + GError *error = NULL; + g_thread_try_new(NULL, (GThreadFunc)dbus_call_handler, (void *)arg, &error); + if (error != NULL) { + _FLOGE("Failed to create thread: %s", error->message); + goto fail; + } + + return TRUE; + +fail: + if (arg) + free(arg); + + org_tizen_update_manager_complete_finish_update(skeleton, invocation, -1); + return TRUE; +} - _FLOGD("Dbus status : install called"); - pid_t pid = dbus_get_sender_pid(invocation); - ret = fota_installer_execute(pid); - if (ret < 0) - _FLOGW("Failed to install delta with fota : %d", ret); - org_tizen_update_manager_complete_install(skeleton, invocation, ret); +/* + * This is not supposed to be called asynchronously, so this doesn't need a separate thread. + * This new thread is only for consistency with functions above. + */ +gboolean dbus_manager_ro_update_and_finish_update(OrgTizenUpdateManager *skeleton, GDBusMethodInvocation *invocation) +{ + _FLOGD("Dbus status: called"); + dbus_handler_arg *arg = (dbus_handler_arg *)malloc(sizeof(dbus_handler_arg)); + if (!arg) { + _FLOGE("Failed to malloc"); + goto fail; + } + + arg->action = RO_UPDATE_AND_FINISH; + arg->skeleton = skeleton; + arg->invocation = invocation; + + GError *error = NULL; + g_thread_try_new(NULL, (GThreadFunc)dbus_call_handler, (void *)arg, &error); + if (error != NULL) { + _FLOGE("Failed to create thread: %s", error->message); + goto fail; + } return TRUE; + +fail: + if (arg) + free(arg); + + org_tizen_update_manager_complete_ro_update_and_finish_update(skeleton, invocation, -1); + return TRUE; } void dbus_manager_on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data) { - _CLOGD("Dbus status : name lost"); + _CLOGD("Dbus status: name lost"); } void dbus_manager_on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { - _CLOGD("Dbus status : name acquired"); + _CLOGD("Dbus status: name acquired"); OrgTizenUpdateManager *skeleton = org_tizen_update_manager_skeleton_new(); - g_signal_connect(skeleton, "handle-install", G_CALLBACK(dbus_manager_install), NULL); + + g_signal_connect(skeleton, "handle-ro-update", G_CALLBACK(dbus_manager_ro_update), NULL); + g_signal_connect(skeleton, "handle-finish-update", G_CALLBACK(dbus_manager_finish_update), NULL); + g_signal_connect(skeleton, "handle-ro-update-and-finish-update", G_CALLBACK(dbus_manager_ro_update_and_finish_update), NULL); + g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(skeleton), connection, DBUS_NODE_NAME, NULL); } void dbus_manager_on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { - _CLOGD("Dbus status : bus acquired"); + _CLOGD("Dbus status: bus acquired"); } int dbus_manager_init() diff --git a/update-manager/fota/fota-installer.c b/update-manager/fota/fota-installer.c index b0d7953..82d0e61 100644 --- a/update-manager/fota/fota-installer.c +++ b/update-manager/fota/fota-installer.c @@ -9,6 +9,11 @@ #define FOTA_TRIGGER_FILE "upgrade-trigger.sh" #define FOTA_TRIGGER_PATH FOTA_DIR "/" FOTA_TRIGGER_FILE +/* Empty string here is intentional */ +#define FOTA_TRIGGER_MODE_RO_UPDATE_AND_FINISH_UPDATE "" +#define FOTA_TRIGGER_MODE_RO_UPDATE "--ro-update" +#define FOTA_TRIGGER_MODE_FINISH_UPDATE "--finish" + #define FOTA_INSTALL_REBOOT_REASON "fota" static char *get_sender_appid(pid_t pid) @@ -71,62 +76,54 @@ static char *find_delta_dir(const char *appid) return client_delta_path; } -int fota_installer_execute(pid_t sender_pid) +int find_delta_and_prepare_script(pid_t sender_pid, gchar **client_delta_path) { - int ret = 0, status = 0, exec_status = 0; + int ret = 0; char *appid = NULL; - gchar *client_delta_path = NULL; - pid_t pid; bool check_sha = false; /* Check client have delta.tar */ appid = get_sender_appid(sender_pid); /* Find the delta file path */ - client_delta_path = find_delta_dir(appid); + *client_delta_path = find_delta_dir(appid); if (appid != NULL) { free(appid); appid = NULL; } - if (client_delta_path == NULL) { + if (*client_delta_path == NULL) { _FLOGE("Delta file not found"); - status = -2; - goto execute_destroy; + return -1; } - _FLOGI("Delta found: %s", client_delta_path); + _FLOGI("Delta found: %s", *client_delta_path); /* Prepare fota dir */ ret = util_file_mkdir(FOTA_DIR); if (ret < 0) { - status = -1; - goto execute_destroy; + return -1; } /* Check client have appropriate delta */ - if (check_is_delta_appropriate(client_delta_path, &check_sha) != 0) { - status = -1; - goto execute_destroy; + if (check_is_delta_appropriate(*client_delta_path, &check_sha) != 0) { + return -1; } /* Setup local update flag */ ret = util_file_mkdir(FOTA_STATUS_DIR); if (ret < 0) { - status = -1; - goto execute_destroy; + return -1; } ret = util_file_write_line(FOTA_STATUS_FLAG_PATH, NULL); if (ret < 0) { - status = -1; - goto execute_destroy; + return -1; } /* Trigger update */ - ret = util_file_untar(client_delta_path, FOTA_DIR, FOTA_TRIGGER_FILE); + ret = util_file_untar(*client_delta_path, FOTA_DIR, FOTA_TRIGGER_FILE); if (ret < 0) { - status = -1; - goto execute_destroy; + return -1; } if (check_sha) { @@ -134,12 +131,29 @@ int fota_installer_execute(pid_t sender_pid) if (verify_checksum(FOTA_CHECKSUM_PATH, FOTA_TRIGGER_PATH) == 0) { _FLOGI("Checksum of %s is correct", FOTA_TRIGGER_PATH); } else { - status = -1; _FLOGE("Failed checksum verification of %s", FOTA_TRIGGER_PATH); - goto execute_destroy; + return -1; } } + return 0; +} + +int fota_installer_ro_update_and_finish_update(pid_t sender_pid) +{ + int ret = 0, status = 0, exec_status = 0; + gchar *client_delta_path = NULL; + pid_t pid; + + ret = find_delta_and_prepare_script(sender_pid, &client_delta_path); + if (ret < 0) { + status = ret; + goto execute_destroy; + } + + /* This shouldn't fail. Added to make compiler happy */ + assert(client_delta_path); + /* All basic checks succeeded, following is what happens next: We * double-fork() the process and run actual upgrade script in the child * process. We do this so that we can at least inform API client that @@ -162,9 +176,12 @@ int fota_installer_execute(pid_t sender_pid) exit(EXIT_SUCCESS); } - ret = execl(FOTA_TRIGGER_PATH, FOTA_TRIGGER_PATH, client_delta_path, NULL); + ret = execl(FOTA_TRIGGER_PATH, FOTA_TRIGGER_PATH, client_delta_path, + FOTA_TRIGGER_MODE_RO_UPDATE_AND_FINISH_UPDATE, NULL); + if (ret == -1) - _FLOGE("Failed to execl(%s %s)", FOTA_TRIGGER_PATH, client_delta_path); + _FLOGE("Failed to execl(%s %s %s)", FOTA_TRIGGER_PATH, client_delta_path, + FOTA_TRIGGER_MODE_RO_UPDATE_AND_FINISH_UPDATE); exit(EXIT_FAILURE); } @@ -184,3 +201,93 @@ execute_destroy: return status; } + +int fota_installer_ro_update(pid_t sender_pid) +{ + int ret = 0, status = 0, exec_status = 0; + gchar *client_delta_path = NULL; + pid_t pid; + + ret = find_delta_and_prepare_script(sender_pid, &client_delta_path); + if (ret < 0) { + status = ret; + goto execute_destroy; + } + + /* This shouldn't fail. Added to make compiler happy */ + assert(client_delta_path); + + /* + * This is supposed to bo called asynchronously, so we do + * care if and when the script finishes. + */ + pid = fork(); + if (pid < 0) { + _FLOGE("Failed to fork"); + status = -1; + goto execute_destroy; + } else if (pid == 0) { + ret = execl(FOTA_TRIGGER_PATH, FOTA_TRIGGER_PATH, client_delta_path, + FOTA_TRIGGER_MODE_RO_UPDATE, NULL); + + if (ret == -1) + _FLOGE("Failed to execl(%s %s %s)", FOTA_TRIGGER_PATH, client_delta_path, + FOTA_TRIGGER_MODE_RO_UPDATE); + + exit(EXIT_FAILURE); + } + + ret = waitpid(pid, &exec_status, 0); + if (ret == -1) { + _FLOGE("Failed to wait child"); + status = -1; + goto execute_destroy; + } + exec_status = WEXITSTATUS(exec_status); + + status = exec_status > 0 ? -exec_status : exec_status; + +execute_destroy: + if (client_delta_path) + free(client_delta_path); + + return status; +} + +int fota_installer_finish_update(void) +{ + int ret = 0, exec_status = 0; + pid_t pid; + + if (verify_checksum(FOTA_CHECKSUM_PATH, FOTA_TRIGGER_PATH) == 0) { + _FLOGI("Checksum of %s is correct", FOTA_TRIGGER_PATH); + } else { + _FLOGE("Failed checksum verification of %s", FOTA_TRIGGER_PATH); + return -1; + } + /* + * This is supposed to bo called asynchronously, so we do + * care if and when the script finishes. + */ + pid = fork(); + if (pid < 0) { + _FLOGE("Failed to fork"); + return -1; + } else if (pid == 0) { + ret = execl(FOTA_TRIGGER_PATH, FOTA_TRIGGER_PATH, FOTA_TRIGGER_MODE_FINISH_UPDATE, NULL); + + if (ret == -1) + _FLOGE("Failed to execl(%s %s)", FOTA_TRIGGER_PATH, FOTA_TRIGGER_MODE_FINISH_UPDATE); + + exit(EXIT_FAILURE); + } + + ret = waitpid(pid, &exec_status, 0); + if (ret == -1) { + _FLOGE("Failed to wait child"); + return -1; + } + exec_status = WEXITSTATUS(exec_status); + + return exec_status > 0 ? -exec_status : exec_status; +} \ No newline at end of file diff --git a/update-manager/fota/fota-manager.h b/update-manager/fota/fota-manager.h index 9f271e1..af36888 100644 --- a/update-manager/fota/fota-manager.h +++ b/update-manager/fota/fota-manager.h @@ -48,7 +48,9 @@ int fota_client_info_checker_init(void); int fota_client_info_checker_fini(void); char *fota_client_info_get_appid(void); -int fota_installer_execute(pid_t pid); +int fota_installer_ro_update_and_finish_update(pid_t sender_pid); +int fota_installer_ro_update(pid_t sender_pid); +int fota_installer_finish_update(void); void fota_storage_checker_plug(int, const char *); void fota_storage_checker_unplug(int, const char *);