00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <glib.h>
00033 #include <glib.h>
00034 #include <signal.h>
00035 #include <stdlib.h>
00036 #include <stdio.h>
00037 #include <string.h>
00038 #include <unistd.h>
00039
00040 #include <hal/libhal.h>
00041
00042
00043 #include <liberkeyb/erkeyb-client.h>
00044
00045
00046 #include "log.h"
00047 #include "busy.h"
00048 #include "conf.h"
00049 #include "connections.h"
00050 #include "display.h"
00051 #include "ipc.h"
00052 #include "hal.h"
00053 #include "process.h"
00054 #include "tasks.h"
00055 #include "xwindow.h"
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 static const gint TIMEOUT_STARTUP_COMPLETED = 30;
00068
00069
00070
00071
00072
00073
00074 static GSList *g_proclist = NULL;
00075 static gint g_process_pending_source = 0;
00076
00077
00078
00079
00080
00081
00082 static void check_start_next(void);
00083 static void on_process_exit(GPid pid, gint status, gpointer data);
00084 static gboolean on_startup_completed_timeout(gpointer data);
00085 static gboolean start_process(proc_t *proc);
00086 static void check_respawn(proc_t *proc);
00087 static void on_reply_error(eripc_context_t *context, const eripc_event_info_t *info, void *user_data);
00088 static void post_process_startup(proc_t *proc, const char *application, gint window);
00089 static proc_t *create_process(const char* command, const char* working_dir, GCallback startup_callback, GCallback exit_callback, gint flags);
00090 static void destroy_process(proc_t *proc);
00091
00092
00093
00094
00095
00096
00097 gboolean process_add(const char* command, const char* working_dir, GCallback startup_callback, GCallback exit_callback, gint flags)
00098 {
00099 LOGPRINTF("entry: %s, %d", command, flags);
00100
00101 proc_t *proc = create_process(command, working_dir, startup_callback, exit_callback, flags);
00102 if (proc == NULL)
00103 {
00104 return FALSE;
00105 }
00106
00107 check_start_next();
00108
00109 return TRUE;
00110 }
00111
00112
00113 proc_t *process_start(const char* command, const char* working_dir, GCallback startup_callback, GCallback exit_callback, gint flags)
00114 {
00115 LOGPRINTF("entry: %s, %d", command, flags);
00116
00117 gboolean result = FALSE;
00118
00119 proc_t *proc = create_process(command, working_dir, startup_callback, exit_callback, flags);
00120 if (proc == NULL)
00121 {
00122 return NULL;
00123 }
00124
00125 result = start_process(proc);
00126 if (result == FALSE)
00127 {
00128 LOGPRINTF("failed to spawn, remove from list");
00129 destroy_process(proc);
00130 proc = NULL;
00131 }
00132
00133 return proc;
00134 }
00135
00136
00137 void process_stop(proc_t *proc)
00138 {
00139 g_assert(proc);
00140 LOGPRINTF("entry: %s, %d", proc->command, proc->pid);
00141
00142 if (proc && proc->pid > 0)
00143 {
00144 kill(proc->pid, SIGTERM);
00145 }
00146 }
00147
00148
00149 gboolean process_activate(const char* application)
00150 {
00151 LOGPRINTF("entry");
00152
00153 gboolean result = FALSE;
00154 Window win_found;
00155
00156 win_found = get_application_window(application);
00157
00158 if (win_found != None)
00159 {
00160 window_activate(win_found);
00161 result = TRUE;
00162 }
00163 else
00164 {
00165 WARNPRINTF("No window found for: %s", application);
00166 }
00167
00168 return result;
00169 }
00170
00171
00172 gboolean process_activate_ctb()
00173 {
00174 LOGPRINTF("entry");
00175
00176 gboolean retval = TRUE;
00177
00178 if (sys_get_device_state() == STATE_DEVICE_STOPPING)
00179 {
00180
00181 return FALSE;
00182 }
00183
00184
00185 gchar *app_active = display_get_active_window();
00186 if (app_active && strcmp(app_active, "ctb") != 0 )
00187 {
00188 retval = process_activate("ctb");
00189 }
00190
00191 return retval;
00192 }
00193
00194
00195 gboolean process_startup_complete(const char *application, gint pid, gboolean is_multidoc, const char *ipc_service, gint window)
00196 {
00197 LOGPRINTF("entry");
00198 gboolean retval = FALSE;
00199
00200
00201 proc_t *proc = process_get_by_pid(pid);
00202
00203 if (proc == NULL)
00204 {
00205 WARNPRINTF("%s (pid %d) is not started sysd", application, pid);
00206 }
00207 else if (proc->state != STATE_STARTING)
00208 {
00209 WARNPRINTF("unexpected startupComplete received from %s (pid %d), state [%d]", application, pid, proc->state);
00210 }
00211 else
00212 {
00213
00214 if (g_process_pending_source)
00215 {
00216 g_source_remove(g_process_pending_source);
00217 g_process_pending_source = 0;
00218 }
00219
00220 LOGPRINTF("received startupComplete from %s (pid %d, window %d), new state STATE_RUNNING", application, pid, window);
00221 if (strcmp(application, "ctb") == 0) {
00222 display_set_ctb_window(window);
00223 }
00224
00225
00226 proc->state = STATE_RUNNING;
00227 proc->is_multidoc = is_multidoc;
00228 proc->ipc_service = g_strdup(ipc_service);
00229
00230
00231 post_process_startup(proc, application, window);
00232
00233
00234 if (proc->startup_callback)
00235 {
00236 (proc->startup_callback)();
00237 }
00238
00239
00240 check_start_next();
00241
00242 retval = TRUE;
00243 }
00244 return retval;
00245 }
00246
00247
00248 proc_t *process_get_by_pid(GPid pid)
00249 {
00250 LOGPRINTF("entry pid [%d]", pid);
00251
00252 GSList *proc_ptr = g_proclist;
00253 proc_t *cur_proc = NULL;
00254
00255 while (proc_ptr)
00256 {
00257 cur_proc = (proc_t *) proc_ptr->data;
00258
00259 if (cur_proc->pid == pid)
00260 {
00261 LOGPRINTF("found [%p] command [%s] ipc service [%s]", cur_proc, cur_proc->command, cur_proc->ipc_service);
00262 return cur_proc;
00263 }
00264
00265 proc_ptr = proc_ptr->next;
00266 }
00267
00268 return NULL;
00269 }
00270
00271 #if (TESTING_ON)
00272 void print_process_list()
00273 {
00274 GSList *proc_ptr = g_proclist;
00275
00276 printf("%s() PROCESS LIST:\n", __func__);
00277 int i = 0;
00278 while (proc_ptr)
00279 {
00280 proc_t *cur = (proc_t *) proc_ptr->data;
00281 printf(" [%d] cmd=%s ipc=%s multi=%d pid=%d\n", i,
00282 cur->command, cur->ipc_service, cur->is_multidoc, cur->pid);
00283
00284 proc_ptr = proc_ptr->next;
00285 i++;
00286 }
00287 }
00288 #endif
00289
00290 proc_t *process_get_by_name(const char *application)
00291 {
00292 LOGPRINTF("entry [%s]", application);
00293
00294 GSList *proc_ptr = g_proclist;
00295
00296 while (proc_ptr)
00297 {
00298 proc_t *cur_proc = (proc_t *) proc_ptr->data;
00299
00300 gint argc = 0;
00301 char **argv_ptr = NULL;
00302 if (g_shell_parse_argv(cur_proc->command, &argc, &argv_ptr, NULL))
00303 {
00304 gchar *proc_app = g_path_get_basename(argv_ptr[0]);
00305
00306 if (application && proc_app && (strcmp(proc_app, application) == 0))
00307 {
00308
00309 g_free(proc_app);
00310 return cur_proc;
00311 }
00312 g_free(proc_app);
00313 g_strfreev(argv_ptr);
00314 }
00315 proc_ptr = proc_ptr->next;
00316 }
00317
00318 return NULL;
00319 }
00320
00321
00322
00323
00324
00325
00326 static proc_t *create_process(const char* command, const char* working_dir, GCallback startup_callback, GCallback exit_callback, gint flags)
00327 {
00328 LOGPRINTF("entry: %s, %d", command, flags);
00329
00330 proc_t *proc = g_new0 (proc_t, 1);
00331 if (!proc)
00332 {
00333 ERRORPRINTF("mem alloc failed");
00334 return NULL;
00335 }
00336
00337
00338
00339 proc->command = g_strdup(command);
00340 proc->working_dir = NULL;
00341 if (working_dir)
00342 {
00343 proc->working_dir = g_strdup(working_dir);
00344 }
00345 proc->ipc_service = NULL;
00346 proc->pid = 0;
00347 proc->is_multidoc = FALSE;
00348 proc->flags = flags;
00349 proc->startup_callback = startup_callback;
00350 proc->exit_callback = exit_callback;
00351 proc->state = STATE_IDLE;
00352
00353
00354 g_proclist = g_slist_append(g_proclist, proc);
00355
00356 return proc;
00357 }
00358
00359
00360 static void destroy_process(proc_t *proc)
00361 {
00362
00363 g_proclist = g_slist_remove(g_proclist, proc);
00364
00365
00366 g_free(proc->command);
00367 g_free(proc->ipc_service);
00368 g_free(proc->working_dir);
00369 g_free(proc);
00370 proc = NULL;
00371 }
00372
00373
00374 static void on_process_exit(GPid pid, gint status, gpointer data)
00375 {
00376 LOGPRINTF("entry");
00377
00378 #if (WARNING_ON)
00379
00380 const char *status_text[] = { "", "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL",
00381 "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE",
00382 "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE",
00383 "SIGALRM", "SIGTERM", "SIGSTKFLT", "SIGCHLD", 0};
00384 if (WIFSIGNALED(status))
00385 {
00386 WARNPRINTF("pid %d was terminated by signal %d [%s]", pid, WTERMSIG(status),
00387 WTERMSIG(status) <= 17 ? status_text[WTERMSIG(status)] : "");
00388 }
00389 else if (WIFEXITED(status))
00390 {
00391 WARNPRINTF("pid %d has exited with status %d", pid, WEXITSTATUS(status));
00392 }
00393 else
00394 {
00395
00396 WARNPRINTF("pid %d is gone, status %d", pid, status);
00397 }
00398 #endif
00399
00400 proc_t *proc = data;
00401 gboolean try_respawn = TRUE;
00402
00403 g_return_if_fail(proc != NULL);
00404 g_return_if_fail(proc->pid == pid);
00405 gchar *proc_app = g_path_get_basename(proc->command);
00406
00407 if (proc->state == STATE_STARTING)
00408 {
00409
00410 if (g_process_pending_source)
00411 {
00412 g_source_remove(g_process_pending_source);
00413 g_process_pending_source = 0;
00414 }
00415
00416
00417
00418
00419 proc->flags &= ~(PS_RESPAWN);
00420
00421 ERRORPRINTF("application [%s] exited", proc->command);
00422 }
00423
00424
00425
00426
00427 if (proc_app &&
00428 ((strcmp(proc_app, "downloadmgr") == 0) || (strcmp(proc_app, "adobe-fulfill") == 0)))
00429 {
00430 ipc_refresh_ctb();
00431 }
00432
00433
00434 task_cleanup_pid(pid);
00435
00436
00437 busy_reset_pid(pid);
00438
00439
00440 display_cleanup_pid(pid);
00441
00442
00443 if ((status !=0) && proc->ipc_service)
00444 {
00445 conn_disconnect(proc->ipc_service);
00446 }
00447
00448
00449 if (proc->exit_callback)
00450 {
00451 (proc->exit_callback)();
00452 }
00453
00454 if (((WIFEXITED(status) && WEXITSTATUS(status) == 1) ||
00455 (WIFSIGNALED(status) &&
00456 (WTERMSIG(status) == SIGFPE || WTERMSIG(status) == SIGABRT || WTERMSIG(status) == SIGSEGV))) &&
00457 proc_app)
00458 {
00459
00460 if (strcmp(proc_app, "uds") == 0)
00461 {
00462 if (sys_get_card() == STATE_CARD_INDEXING)
00463 {
00464
00465 system("killall mdbindex");
00466 ipc_show_message("indexerror", on_reply_error, proc);
00467
00468 try_respawn = FALSE;
00469 }
00470 else
00471 {
00472 ipc_show_message("udserror", on_reply_error, proc);
00473
00474 try_respawn = FALSE;
00475 }
00476 }
00477 else if (strcmp(proc_app, "erbrowser") == 0)
00478 {
00479 erkeyb_client_hide();
00480 ipc_show_message("browsererror", NULL, NULL);
00481 }
00482 }
00483
00484 if (try_respawn)
00485 {
00486 check_respawn(proc);
00487 }
00488 g_free(proc_app);
00489 }
00490
00491
00492 static void check_respawn(proc_t *proc)
00493 {
00494 GPid pid = proc->pid;
00495
00496 if (proc->flags & PS_RESPAWN)
00497 {
00498 LOGPRINTF("should respawn, new state STATE_IDLE");
00499 WARNPRINTF("respawn application %s", proc->command);
00500
00501 proc->state = STATE_IDLE;
00502 proc->pid = 0;
00503 g_free(proc->ipc_service);
00504 proc->ipc_service = NULL;
00505
00506 proc->startup_callback = NULL;
00507 proc->exit_callback = NULL;
00508 }
00509 else
00510 {
00511 LOGPRINTF("no respawn, remove from list");
00512 destroy_process(proc);
00513 proc = NULL;
00514 }
00515
00516
00517 g_spawn_close_pid(pid);
00518
00519 if (sys_get_device_state() != STATE_DEVICE_STOPPING)
00520 {
00521
00522 check_start_next();
00523 }
00524 }
00525
00526
00527 static gboolean on_startup_completed_timeout(gpointer data)
00528 {
00529 proc_t *proc = data;
00530
00531 LOGPRINTF("entry");
00532 LOGPRINTF("timeout waiting for startupComplete (%s), new state STATE_RUNNING", proc->command);
00533
00534
00535 proc->state = STATE_RUNNING;
00536
00537
00538 check_start_next();
00539
00540 g_process_pending_source = 0;
00541
00542
00543 return FALSE;
00544 }
00545
00546
00547 static void check_start_next()
00548 {
00549 LOGPRINTF("entry");
00550
00551 proc_t *cur_proc = NULL;
00552 GSList *proc_ptr = g_proclist;
00553 gboolean is_ready = TRUE;
00554
00555 if (sys_get_device_state() == STATE_DEVICE_STOPPING)
00556 {
00557 WARNPRINTF("device is shutting down, process not started");
00558 return;
00559 }
00560
00561 while (proc_ptr)
00562 {
00563 cur_proc = (proc_t *) proc_ptr->data;
00564
00565 if (((cur_proc->state == STATE_STARTING) && (cur_proc->flags & PS_WAIT_STARTED)) ||
00566 ((cur_proc->state == STATE_RUNNING) && (cur_proc->flags & PS_WAIT_EXIT)))
00567 {
00568 LOGPRINTF("wait for process %d to complete", cur_proc->pid);
00569 is_ready = FALSE;
00570 break;
00571 }
00572
00573 proc_ptr = proc_ptr->next;
00574 }
00575
00576 if (is_ready)
00577 {
00578 proc_ptr = g_proclist;
00579
00580 while (proc_ptr)
00581 {
00582 cur_proc = (proc_t *) proc_ptr->data;
00583
00584 if (cur_proc->state == STATE_IDLE)
00585 {
00586 LOGPRINTF("start next process: %s", cur_proc->command);
00587 start_process(cur_proc);
00588 return;
00589 }
00590
00591 proc_ptr = proc_ptr->next;
00592 }
00593 }
00594 return;
00595 }
00596
00597
00598 static gboolean start_process(proc_t *proc)
00599 {
00600 LOGPRINTF("entry");
00601
00602 GPid child_pid = 0;
00603 gint argc = 0;
00604 char **argv_ptr = NULL;
00605 gboolean retval = FALSE;
00606 GError *error = NULL;
00607
00608 LOGPRINTF("Starting: %s", proc->command);
00609
00610 retval = g_shell_parse_argv(proc->command, &argc, &argv_ptr, &error);
00611 if (error)
00612 {
00613 WARNPRINTF("Error parsing command '%s' failed with error: %s", proc->command, error->message);
00614 g_error_free(error);
00615 return FALSE;
00616 }
00617
00618 retval = g_spawn_async(proc->working_dir, argv_ptr, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &child_pid, &error);
00619 if (error)
00620 {
00621 WARNPRINTF("Execution of '%s' failed with error: %s", proc->command, error->message);
00622 g_error_free(error);
00623 if (argv_ptr) g_strfreev(argv_ptr);
00624 return FALSE;
00625 }
00626
00627 if (proc->flags & PS_WAIT_STARTED)
00628 {
00629 if (g_process_pending_source)
00630 {
00631 g_source_remove(g_process_pending_source);
00632 WARNPRINTF("A process is started while a previous one was still pending. Previous pending timer stopped.");
00633 }
00634
00635
00636 g_process_pending_source = g_timeout_add_seconds(TIMEOUT_STARTUP_COMPLETED, on_startup_completed_timeout, proc);
00637
00638
00639 LOGPRINTF("wait for startupComplete (pid %d), new state STATE_STARTING", child_pid);
00640 proc->state = STATE_STARTING;
00641 proc->pid = child_pid;
00642 }
00643 else
00644 {
00645
00646 LOGPRINTF("don't wait for startup, new state STATE_RUNNING");
00647 proc->state = STATE_RUNNING;
00648 proc->pid = child_pid;
00649
00650 if (!(proc->flags & PS_WAIT_EXIT))
00651 {
00652
00653 check_start_next();
00654 }
00655 }
00656
00657
00658 g_child_watch_add(child_pid, on_process_exit, proc);
00659
00660 g_strfreev(argv_ptr);
00661 return TRUE;
00662 }
00663
00664
00665 static void post_process_startup(proc_t *proc, const char *application, gint window)
00666 {
00667 LOGPRINTF("entry");
00668
00669
00670 task_startup_completed(proc, window);
00671
00672
00673 if (sys_get_card() == STATE_CARD_MOUNTED)
00674 {
00675 ipc_send_volume_mounted_to(proc->ipc_service, MOUNTPOINT_CARD);
00676 }
00677
00678
00679 const char *locale = g_getenv("LANG");
00680 if (locale)
00681 {
00682 ipc_send_changed_locale(locale);
00683 }
00684 }
00685
00686
00687 static void on_reply_error(eripc_context_t *context,
00688 const eripc_event_info_t *info,
00689 void *user_data)
00690 {
00691 LOGPRINTF("entry");
00692
00693 const eripc_arg_t *arg_array = info->args;
00694
00695 if (info->event_type != ERIPC_EVENT_REPLY)
00696 {
00697 WARNPRINTF("invalid event: %d", info->event_type);
00698 }
00699 else if ((arg_array == NULL) || (arg_array[0].type != ERIPC_TYPE_BOOL))
00700 {
00701 WARNPRINTF("invalid arguments in reply");
00702 }
00703 else
00704 {
00705 LOGPRINTF("User clicked ok");
00706 proc_t *proc = user_data;
00707 check_respawn(proc);
00708 }
00709 }