/**
* @brief Enumeration for the update control error.
- * @since_tizen 5.0
+ * @since_tizen 9.0
*/
typedef enum {
UPDATE_CONTROL_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
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, /**<Device or resource busy */
UPDATE_CONTROL_ERROR_INVALID_OPERATION = TIZEN_ERROR_INVALID_OPERATION, /**< Function not implemented */
UPDATE_CONTROL_ERROR_INVALID_PACKAGE = TIZEN_ERROR_UPDATE_CONTROL | 0x01, /**< Invalid package */
UPDATE_CONTROL_ERROR_INVALID_URI = TIZEN_ERROR_UPDATE_CONTROL | 0x02, /**< Invalid URI */
UPDATE_CONTROL_ERROR_PACKAGE_NOT_SUPPORTED = TIZEN_ERROR_UPDATE_CONTROL | 0x03, /**< Package type not supported */
UPDATE_CONTROL_ERROR_SYSTEM_ERROR = TIZEN_ERROR_UPDATE_CONTROL | 0x04, /**< System error */
+ UPDATE_CONTROL_ERROR_RO_UPDATE_IN_PROGRESS = TIZEN_ERROR_UPDATE_CONTROL | 0x05, /**< RO update is in progress */
+ UPDATE_CONTROL_ERROR_RO_UPDATE_NOT_COMPLETED = TIZEN_ERROR_UPDATE_CONTROL | 0x06, /**< RO update has not completed */
} update_control_error_e;
} update_control_property_e;
+
+/**
+ * @brief Callback type to be invoked after the RO update or the finish update process finishes.
+ * @details The callback will be triggered when the operation triggered by update_control_do_ro_update() \n
+ * or update_control_do_finish_update() finishes (does not have to be successful). Examine the \p result parameter \n
+ * to get the result of the operation. Both RO update and finish update operations can have following results:
+ * - #UPDATE_CONTROL_ERROR_NONE Successful
+ * - #UPDATE_CONTROL_ERROR_SYSTEM_ERROR System error
+ * - #UPDATE_CONTROL_ERROR_INVALID_OPERATION Upgrade script returned an error
+ * - #UPDATE_CONTROL_ERROR_NOT_SUPPORTED Not supported
+ * Finish update operation can additionally result in following:
+ * - #UPDATE_CONTROL_RO_UPDATE_IN_PROGRESS - RO update is still in progress
+ * - #UPDATE_CONTROL_ERROR_RO_UPDATE_NOT_COMPLETED - RO update has not finished (and is not currently in progress), \n
+ * most likely meaning the RO update has not been triggered yet
+ *
+ * @since_tizen 9.0
+ * @remarks This callback will be invoked in the main event loop of the client.
+ * @param[in] result Result of the operation that triggered the callback
+ * @param[in] user_data User data given when setting the callback
+ * @pre Register the callback using update_control_set_ro_update_cb() or update_control_set_finish_update_cb(). \n
+ * The callback will be invoked only when the operation associated with the registering function finishes. \n
+ * @see update_control_set_ro_update_cb()
+ * @see update_control_set_finish_update_cb()
+ * @see update_control_unset_ro_update_cb()
+ * @see update_control_unset_finish_update_cb()
+ * @see update_control_do_ro_update()
+ * @see update_control_do_finish_update()
+ */
+typedef void (*update_control_cb) (const update_control_error_e result, const void *user_data);
+
+
/**
* @brief Initializes the update controller.
*
/**
* @platform
- * @brief Requests triggering update to new firmware.
- *
+ * @brief Triggers upgrade script and tells it to perform RO update and finish update operations (full upgrade process).
+ * @details This starts the script in the background and quickly returns. It doesn't check the return value of the script.
* @since_tizen 5.0
* @privlevel platform
* @privilege %http://tizen.org/privilege/updatecontrol.admin
- * @return @c 0 on success,
+ * @return @c 0 if RO update and finish were triggered successfully (doesn't guarantee upgrade script COMPLETED successfully),
* otherwise a negative error value
* @retval #UPDATE_CONTROL_ERROR_NONE Successful
* @retval #UPDATE_CONTROL_ERROR_PERMISSION_DENIED Permission denied
int update_control_do_update(void);
+/**
+ * @brief Sets a callback to trigger once RO update has completed.
+ *
+ * @since_tizen 9.0
+ * @remarks If there already is a callback set using this function, calling it again will overwrite it.
+ * @param[in] user_cb The callback to be triggered once the operation has completed
+ * @param[in] user_data Data to be passed to the callback
+ * @return @c 0 if callback was set, otherwise a negative error value
+ * @retval #UPDATE_CONTROL_ERROR_NONE Successful
+ * @retval #UPDATE_CONTROL_ERROR_NOT_SUPPORTED Not supported
+ * @retval #UPDATE_CONTROL_ERROR_INVALID_PARAMETER @user_cb is null
+ * @retval #UPDATE_CONTROL_ERROR_SYSTEM_ERROR System error
+ * @post @user_cb will be called after an operation launched by update_control_do_ro_update_async() finishes.
+ * @see update_control_unset_ro_update_cb()
+ * @see update_control_do_ro_update_async()
+ */
+int update_control_set_ro_update_cb(update_control_cb user_cb, const void* user_data);
+
+
+/**
+ * @brief Unsets the callback set by update_control_set_ro_update_cb().
+ *
+ * @since_tizen 9.0
+ * @remarks Using this function after launching associated operation but before \n
+ * receiving the callback will not cause any errors, but will make tracking the result of \n
+ * the operation impossible.
+ * @return @c 0 if callback was unset, otherwise a negative error value
+ * @retval #UPDATE_CONTROL_ERROR_NONE Successful
+ * @retval #UPDATE_CONTROL_ERROR_NOT_SUPPORTED Not supported
+ * @retval #UPDATE_CONTROL_ERROR_SYSTEM_ERROR System error
+ * @retval #UPDATE_CONTROL_ERROR_INVALID_OPERATION No callback to unset
+ * @pre A callback has to be set using update_control_set_ro_update_cb() before calling \n
+ * this function.
+ * @see update_control_set_ro_update_cb()
+ */
+int update_control_unset_ro_update_cb(void);
+
+
+/**
+ * @platform
+ * @brief Triggers upgrade script and tells it to perform @b ONLY RO update asynchronously.
+ * @details This function does not perform the finishing of update process (among others rebooting). \n
+ * To finish the update use update_control_do_finish_update_async(). If you wish to trigger both operations synchronously, \n
+ * use update_control_do_update().
+ *
+ * @since_tizen 9.0
+ * @privlevel platform
+ * @privilege %http://tizen.org/privilege/updatecontrol.admin
+ * @return @c 0 if basic checks succeeded (does not guarantee the operation triggered completed successfully), \n
+ * otherwise a negative error value
+ * @retval #UPDATE_CONTROL_ERROR_NONE Successful
+ * @retval #UPDATE_CONTROL_ERROR_NOT_SUPPORTED Not supported
+ * @retval #UPDATE_CONTROL_ERROR_PERMISSION_DENIED Permission denied
+ * @retval #UPDATE_CONTROL_ERROR_SYSTEM_ERROR System error
+ * @retval #UPDATE_CONTROL_ERROR_INVALID_OPERATION Callback was not set
+ * @pre update_control_initialize() has to be called before calling this function.
+ * @pre A callback has to be set using update_control_set_ro_update_cb() before calling \n
+ * this function.
+ * @post A callback set by update_control_set_ro_update_cb() will be invoked \n
+ * after RO update finishes (does not guarantee the process was successful). \n
+ * To check the result of the operation, examine the result code passed to the callback.
+ * @see update_control_initialize()
+ * @see update_control_set_ro_update_cb()
+ */
+int update_control_do_ro_update_async(void);
+
+
+/**
+ * @brief Sets a callback to trigger once finish update operation has completed.
+ *
+ * @since_tizen 9.0
+ * @remarks If there already is a callback set using this function, calling it again will overwrite it.
+ * @param[in] user_cb The callback to be triggered once the operation has completed
+ * @param[in] user_data Data to be passed to the callback
+ * @return @c 0 if callback was set, otherwise a negative error value
+ * @retval #UPDATE_CONTROL_ERROR_NONE Successful
+ * @retval #UPDATE_CONTROL_ERROR_NOT_SUPPORTED Not supported
+ * @retval #UPDATE_CONTROL_ERROR_INVALID_PARAMETER @user_cb is null
+ * @retval #UPDATE_CONTROL_ERROR_SYSTEM_ERROR System error
+ * @post @user_cb will be called after an operation launched by update_control_do_finish_update_async() finishes.
+ * @see update_control_unset_finish_update_cb()
+ * @see update_control_do_finish_update_async()
+ */
+int update_control_set_finish_update_cb(update_control_cb user_cb, const void* user_data);
+
+
+/**
+ * @brief Unsets the callback set by update_control_set_finish_update_cb().
+ *
+ * @since_tizen 9.0
+ * @remarks Using this function after launching associated operation but before \n
+ * receiving the callback will not cause any errors, but will make tracking the result of \n
+ * the operation impossible.
+ * @return @c 0 if callback was unset, otherwise a negative error value
+ * @retval #UPDATE_CONTROL_ERROR_NONE Successful
+ * @retval #UPDATE_CONTROL_ERROR_NOT_SUPPORTED Not supported
+ * @retval #UPDATE_CONTROL_ERROR_SYSTEM_ERROR System error
+ * @retval #UPDATE_CONTROL_ERROR_INVALID_OPERATION No callback to unset
+ * @pre A callback has to be set using update_control_set_finish_update_cb() before calling \n
+ * this function.
+ * @see update_control_set_finish_update_cb()
+ */
+int update_control_unset_finish_update_cb(void);
+
+
+/**
+ * @platform
+ * @brief Triggers upgrade script and tells it to perform @b ONLY the finish update process asynchronously.
+ * @details This function does not perform the RO update process. \n
+ * To trigger RO use update_control_do_ro_update_async(). If you wish to trigger both operations synchronously, \n
+ * use update_control_do_update().
+ *
+ * @since_tizen 9.0
+ * @privlevel platform
+ * @privilege %http://tizen.org/privilege/updatecontrol.admin
+ * @remarks This function can be used to check whether the RO update process is still in progress.
+ * @return @c 0 if basic checks succeeded (does not guarantee the operation triggered finished successfully), \n
+ * otherwise a negative error value
+ * @retval #UPDATE_CONTROL_ERROR_NONE Successful
+ * @retval #UPDATE_CONTROL_ERROR_NOT_SUPPORTED Not supported
+ * @retval #UPDATE_CONTROL_ERROR_PERMISSION_DENIED Permission denied
+ * @retval #UPDATE_CONTROL_ERROR_SYSTEM_ERROR System error
+ * @retval #UPDATE_CONTROL_ERROR_INVALID_OPERATION Callback was not set
+ * @pre update_control_initialize() has to be called before calling this function.
+ * @pre A callback has to be set using update_control_set_finish_update_cb() before calling \n
+ * this function.
+ * @pre In order for the finish update process to complete successfully, this function has \n
+ * to be called after the RO update process launched by update_control_do_ro_update_async() \n
+ * completes @b SUCCESSFULLY. Calling this function before that will not return an error.
+ * @post A callback set by update_control_set_finish_update_cb() will be invoked \n
+ * after the finish update process finishes. To check the result of the operation, examine \n
+ * the result code passed to the callback. If the process was successful, the callback \n
+ * will not be invoked, because the system will be rebooting.
+ * @see update_control_initialize()
+ * @see update_control_set_finish_update_cb()
+ * @see update_control_do_ro_update_async()
+ */
+int update_control_do_finish_update_async(void);
+
+
/**
* @platform
* @brief Makes reservation for update.
<busconfig>
<policy user="root">
<allow own="org.tizen.update.manager"/>
- <allow send_destination="org.tizen.update.manager" send_interface="org.tizen.update.manager" send_member="install" />
+ <allow send_destination="org.tizen.update.manager" send_interface="org.tizen.update.manager" send_member="RoUpdate" />
+ <allow send_destination="org.tizen.update.manager" send_interface="org.tizen.update.manager" send_member="FinishUpdate" />
+ <allow send_destination="org.tizen.update.manager" send_interface="org.tizen.update.manager" send_member="RoUpdateAndFinishUpdate" />
</policy>
<policy context="default">
<deny own="org.tizen.update.manager"/>
<deny send_destination="org.tizen.update.manager" send_type="method_call"/>
- <check send_destination="org.tizen.update.manager" send_interface="org.tizen.update.manager" send_member="install" privilege="http://tizen.org/privilege/updatecontrol.admin" />
+ <check send_destination="org.tizen.update.manager" send_interface="org.tizen.update.manager" send_member="RoUpdate" privilege="http://tizen.org/privilege/updatecontrol.admin" />
+ <check send_destination="org.tizen.update.manager" send_interface="org.tizen.update.manager" send_member="FinishUpdate" privilege="http://tizen.org/privilege/updatecontrol.admin" />
+ <check send_destination="org.tizen.update.manager" send_interface="org.tizen.update.manager" send_member="RoUpdateAndFinishUpdate" privilege="http://tizen.org/privilege/updatecontrol.admin" />
<allow send_destination="org.tizen.update.manager" send_interface="org.freedesktop.DBus.Properties" send_member="GetAll" />
</policy>
</busconfig>
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/org/tizen/update/manager">
<interface name="org.tizen.update.manager">
- <method name="install">
+ <method name="RoUpdate">
+ <arg name="status" direction="out" type="i" />
+ </method>
+ <method name="FinishUpdate">
+ <arg name="status" direction="out" type="i" />
+ </method>
+ <method name="RoUpdateAndFinishUpdate">
<arg name="status" direction="out" type="i" />
</method>
</interface>
* limitations under the License.
*/
+#include "update_control_internal.h"
+
#include <dlfcn.h>
#include <unistd.h>
-#include "update_control_internal.h"
+
+#include <glib.h>
+#include <gio/gio.h>
#include <system/syscommon-plugin-update-control.h>
#include <system/syscommon-plugin-update-control-interface.h>
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 <RoUpdate> method call failed: %s", error->message);
+ g_error_free(error);
+ result = UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ goto trigger_user_cb;
+ }
+
+ _I("Successfully called DBus <RoUpdate> method");
+ if (status < 0) {
+ _E("DBus method <RoUpdate> 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 <FinishUpdate> method call failed: %s", error->message);
+ g_error_free(error);
+ result = UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+ goto trigger_user_cb;
+ }
+
+ _I("Successfully called DBus <FinishUpdate> 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 <FinishUpdate> 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);
_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;
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 <install> method: %s", error->message);
+ _E("Failed to call DBus <RoUpdateAndFinishUpdate> method: %s", error->message);
g_error_free(error);
return UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
}
- _I("Successfully called DBus <install> method call");
+ _I("Successfully called DBus <RoUpdateAndFinishUpdate> method call");
if (status < 0) {
- _E("DBus method <install> returned error code: %d", status);
+ _E("DBus method <RoUpdateAndFinishUpdate> returned error code: %d", status);
return UPDATE_CONTROL_ERROR_INVALID_OPERATION;
}
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 <RoUpdate> 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 <FinishUpdate> method asynchronously");
+
+ return UPDATE_CONTROL_ERROR_NONE;
+}
+
API int update_control_make_reservation(struct tm *reservation_time)
{
CHECK_FEATURE_SUPPORTED(DEVICE_UPDATE_FEATURE);
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);
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 <RoUpdate>: %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 <FinishUpdate>: %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 <RoUpdateAndFinishUpdate>: %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: <RoUpdate> 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: <FinishUpdate> 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: <RoUpdateAndFinishUpdate> 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()
#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)
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) {
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
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);
}
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
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 *);