+static int
+_process_dead_tracker (int pid, void *data)
+{
+ A11yBusLauncher *app = data;
+
+ if (app->screen_reader.pid > 0 && pid == app->screen_reader.pid)
+ {
+ LOGE("screen reader is dead, pid: %d, restarting", pid);
+ app->screen_reader.pid = 0;
+ g_timeout_add_seconds (2, _launch_process_repeat_until_success, &app->screen_reader);
+ }
+
+ if (app->universal_switch.pid > 0 && pid == app->universal_switch.pid)
+ {
+ LOGE("universal switch is dead, pid: %d, restarting", pid);
+ app->universal_switch.pid = 0;
+ g_timeout_add_seconds (2, _launch_process_repeat_until_success, &app->universal_switch);
+ }
+ return 0;
+}
+
+static void
+_register_process_dead_tracker ()
+{
+ if(_global_app->screen_reader.pid > 0 || _global_app->universal_switch.pid > 0) {
+ LOGD("registering process dead tracker");
+ aul_listen_app_dead_signal(_process_dead_tracker, _global_app);
+ } else {
+ LOGD("unregistering process dead tracker");
+ aul_listen_app_dead_signal(NULL, NULL);
+ }
+}
+
+
+static gboolean
+_launch_client(A11yBusClient *client, gboolean by_vconf_change)
+{
+ LOGD("Launching %s", client->name);
+
+ bundle *kb = NULL;
+ gboolean ret = FALSE;
+
+ kb = bundle_create();
+
+ if (kb == NULL)
+ {
+ LOGD("Can't create bundle");
+ return FALSE;
+ }
+
+ if (by_vconf_change)
+ {
+ if (bundle_add_str(kb, "by_vconf_change", "yes") != BUNDLE_ERROR_NONE)
+ {
+ LOGD("Can't add information to bundle");
+ }
+ }
+
+ int operation_error = appsvc_set_operation(kb, client->app_control_operation);
+ LOGD("appsvc_set_operation: %i", operation_error);
+
+ client->pid = appsvc_run_service(kb, 0, NULL, NULL);
+
+ if (client->pid > 0)
+ {
+ LOGD("Process launched with pid: %i", client->pid);
+ _register_process_dead_tracker();
+ ret = TRUE;
+ }
+ else
+ {
+ LOGD("Can't start %s - error code: %i", client->name, client->pid);
+ }
+
+ bundle_free(kb);
+ return ret;
+}
+
+static gboolean
+_launch_process_repeat_until_success(gpointer user_data) {
+ A11yBusClient *client = user_data;
+
+ if (client->launch_repeats > 100 || client->pid > 0)
+ {
+ //do not try anymore
+ return FALSE;
+ }
+
+ gboolean ret = _launch_client(client, FALSE);
+
+ if (ret)
+ {
+ //we managed to
+ client->launch_repeats = 0;
+ return FALSE;
+ }
+ client->launch_repeats++;
+ //try again
+ return TRUE;
+}
+
+static gboolean
+_terminate_process(int pid)
+{
+ int ret;
+ int ret_aul;
+ if (pid <= 0)
+ return FALSE;
+
+ int status = aul_app_get_status_bypid(pid);
+
+ if (status < 0)
+ {
+ LOGD("App with pid %d already terminated", pid);
+ return TRUE;
+ }
+
+ LOGD("terminate process with pid %d", pid);
+ ret_aul = aul_terminate_pid(pid);
+ if (ret_aul >= 0)
+ {
+ LOGD("Terminating with aul_terminate_pid: return is %d", ret_aul);
+ return TRUE;
+ }
+ else
+ LOGD("aul_terminate_pid failed: return is %d", ret_aul);
+
+ LOGD("Unable to terminate process using aul api. Sending SIGTERM signal");
+ ret = kill(pid, SIGTERM);
+ if (!ret)
+ {
+ return TRUE;
+ }
+
+ LOGD("Unable to terminate process: %d with api or signal.", pid);
+ return FALSE;
+}
+
+static gboolean
+_terminate_client(A11yBusClient *client)
+{
+ LOGD("Terminating %s", client->name);
+ int pid = client->pid;
+ client->pid = 0;
+ _register_process_dead_tracker();
+ gboolean ret = _terminate_process(pid);
+ return ret;
+}
+
+void vconf_client_cb(keynode_t *node, void *user_data)
+{
+ A11yBusClient *client = user_data;
+
+ gboolean client_needed = FALSE;
+ int i;
+ for (i = 0; i < client->number_of_keys; i++) {
+ int status = 0;
+ int ret =vconf_get_bool(client->vconf_key[i], &status);
+ if (ret != 0)
+ {
+ LOGD("Could not read %s key value.\n", client->vconf_key[i]);
+ return;
+ }
+ LOGD("vconf_keynode_get_bool(node): %i", status);
+ if (status < 0)
+ return;
+
+ if (status == 1) {
+ client_needed = TRUE;
+ break;
+ }
+ }
+
+ //check if process really exists (e.g didn't crash)
+ if (client->pid > 0)
+ {
+ int err = kill(client->pid,0);
+ //process doesn't exist
+ if (err == ESRCH)
+ client->pid = 0;
+ }
+
+ LOGD("client_needed: %i, client->pid: %i", client_needed, client->pid);
+ if (!client_needed && (client->pid > 0))
+ _terminate_client(client);
+ else if (client_needed && (client->pid <= 0))
+ _launch_client(client, TRUE);
+}
+
+
+static gboolean register_executable(A11yBusClient *client)
+{
+ gboolean client_needed = FALSE;
+
+ int i;
+ for (i = 0; i < client->number_of_keys; i++) {
+ if (!client->vconf_key[i]) {
+ LOGE("Vconf_key missing for client: %d \n", i);
+ return FALSE;
+ }
+
+ int status = 0;
+ int ret = vconf_get_bool(client->vconf_key[i], &status);
+ if (ret != 0)
+ {
+ LOGD("Could not read %s key value.\n", client->vconf_key[i]);
+ return FALSE;
+ }
+ ret = vconf_notify_key_changed(client->vconf_key[i], vconf_client_cb, client);
+ if (ret != 0)
+ {
+ LOGD("Could not add information level callback\n");
+ return FALSE;
+ }
+ if (status)
+ client_needed = TRUE;
+ }
+
+ if (client_needed)
+ g_timeout_add_seconds(2,_launch_process_repeat_until_success, client);
+ return TRUE;
+}
+