Do not track the full upgrade server-side 68/278868/7 accepted/tizen/unified/20220728.044828 submit/tizen/20220727.141559
authorMateusz Majewski <m.majewski2@samsung.com>
Wed, 27 Jul 2022 06:26:13 +0000 (08:26 +0200)
committerMateusz Majewski <m.majewski2@samsung.com>
Wed, 27 Jul 2022 13:00:19 +0000 (15:00 +0200)
This realises the asynchrony of do_update in a better way, since now the
server does some basic checks, and fades away after spawning the update
process.

Change-Id: I4d53f3d65eaf6e75a425bf3061f10fd0b5f55d7a

src/update_control.c
update-manager/fota/fota-installer.c

index 2b769cd790716e441576b2d6e810d169fd8a3da3..d87f787abd8862b8dc416ac63ad926326ad9cca3 100644 (file)
@@ -182,47 +182,33 @@ API int update_control_download_package(void)
        return UPDATE_CONTROL_ERROR_NONE;
 }
 
-static void do_update_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
+API int update_control_do_update(void)
 {
-       if (proxy == NULL) {
-               _E("Not initialized");
-               return;
-       }
+       CHECK_FEATURE_SUPPORTED(DEVICE_UPDATE_FEATURE);
+       _I("update_control_do_update called");
 
        gint status = 0;
        GError *error = NULL;
 
-       org_tizen_update_manager_call_install_finish(proxy, &status, res, &error);
+       if (proxy == NULL) {
+               _E("Not initialized");
+               return UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+       }
+
+       org_tizen_update_manager_call_install_sync(proxy, &status, NULL, &error);
        if (error != NULL) {
-               _E("Failed to method call <install> to dbus : %s", error->message);
+               _E("Failed to call DBus <install> method: %s", error->message);
                g_error_free(error);
-               return;
+               return UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
        }
 
-       _I("Success to method call <install> to dbus");
+       _I("Successfully called DBus <install> method call");
        if (status < 0) {
-               _E("Failed to do update : %d", status);
-               return;
-       }
-
-       // NB: We shouldn't really end up here, since the target should be rebooted by now.
-       _I("Success to do update : %d", status);
-}
-
-API int update_control_do_update(void)
-{
-       CHECK_FEATURE_SUPPORTED(DEVICE_UPDATE_FEATURE);
-       _I("update_control_do_update called");
-
-       if (proxy == NULL) {
-               _E("Not initialized");
-               return UPDATE_CONTROL_ERROR_SYSTEM_ERROR;
+               _E("DBus method <install> returned error code: %d", status);
+               return UPDATE_CONTROL_ERROR_INVALID_OPERATION;
        }
 
-       // TODO: Take the fact that this is now async into account in docs.
-       // TODO: Consider making this asynchronous server-side instead.
-       org_tizen_update_manager_call_install(proxy, NULL, do_update_cb, NULL);
-       _I("Started update");
+       _I("Started update: %d", status);
        return UPDATE_CONTROL_ERROR_NONE;
 }
 
index 1686b5604b53c382e1ebe2c8213f25a71bddc0de..cb68ec22b74c74d69c03e3df959e56b40e4bf366 100644 (file)
@@ -167,12 +167,28 @@ int fota_installer_execute(pid_t sender_pid)
                }
        }
 
+       /* 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
+        * script executed sucessfuly, without requiring him to wait for whole
+        * upgrade to succeed till returning from dbus call.
+        * TODO: Take the fact that this is now async into account in docs. */
        pid = fork();
        if (pid < 0) {
                _FLOGE("Failed to fork");
                status = -1;
                goto execute_destroy;
        } else if (pid == 0) {
+               /* Double fork to avoid zombies */
+               switch (fork()) {
+                       case -1:
+                               exit(EXIT_FAILURE);
+                       case 0:
+                               break;
+                       default:
+                               exit(EXIT_SUCCESS);
+               }
+
                ret = execl(FOTA_TRIGGER_PATH, FOTA_TRIGGER_PATH, client_delta_path, NULL);
                if (ret == -1)
                        _FLOGE("Failed to execl(%s %s)", FOTA_TRIGGER_PATH, client_delta_path);
@@ -180,43 +196,15 @@ int fota_installer_execute(pid_t sender_pid)
                exit(EXIT_FAILURE);
        }
 
-       ret = wait(&exec_status);
+       /* Since we double forked, we have to wait for the first child (otherwise
+        * it will become a zombie), but it should return quickly. */
+       ret = waitpid(pid, &exec_status, 0);
        if (ret == -1) {
                _FLOGE("Failed to wait child");
                status = -1;
                goto execute_destroy;
        }
 
-       if (WIFEXITED(exec_status) == TRUE) {
-               exec_status = WEXITSTATUS(exec_status);
-               if (exec_status != 100) {
-                       _FLOGE("Trigger fota failed, exit code(%d)", exec_status);
-                       status = -4;
-                       goto execute_destroy;
-               }
-       } else if (WIFSIGNALED(exec_status) == TRUE) {
-               _FLOGE("Trigger fota killed, signal(%d)", WTERMSIG(exec_status));
-               status = -4;
-               goto execute_destroy;
-       } else if (WIFSTOPPED(exec_status) == TRUE) {
-               _FLOGE("Trigger fota stoped, signal(%d)", WSTOPSIG(exec_status));
-               status = -4;
-               goto execute_destroy;
-       } else {
-               _FLOGE("Unexpected wait error");
-               status = -1;
-               goto execute_destroy;
-       }
-
-       ret = device_power_reboot(FOTA_INSTALL_REBOOT_REASON);
-       if (ret != DEVICE_ERROR_NONE) {
-               _FLOGE("Failed to reboot with %s", FOTA_INSTALL_REBOOT_REASON);
-               status = -1;
-               goto execute_destroy;
-       }
-
-       _FLOGI("Success to trigger fota, device will be rebooted");
-
 execute_destroy:
        util_file_remove(FOTA_DELTA_BUILD_STRING_PATH);