From: Steven Luo Date: Sun, 30 May 2010 07:58:08 +0000 (-0700) Subject: Fremantle: Coexist with a running MicroB process; don't kill MicroB at end of session... X-Git-Url: http://git.maemo.org/git/?p=browser-switch;a=commitdiff_plain;h=refs%2Fheads%2Ffremantle-microb-improvements Fremantle: Coexist with a running MicroB process; don't kill MicroB at end of session if MicroB is the default browser With commit 07a0e091... ("Tweak detection of com.nokia.osso_browser acquisition slightly"), it's almost possible to support opening a new window in an already-running MicroB. All we have to do is avoid invoking a new browser process in that case, so do that here. It also turns out to be possible to take back the com.nokia.osso_browser D-Bus name from MicroB without killing it, which is interesting to us because the need to kill MicroB is what necessitates the behavior changes we force on MicroB. On the other hand, if we choose to avoid killing MicroB, we lose the ability to have MicroB take over handling osso_browser requests while a MicroB window is open, and we waste memory for users who aren't using MicroB very often. Therefore, we take a compromise approach: if MicroB is set as the default browser, we don't bother killing MicroB when the last browser window closes (which simplifies the code considerably, since we no longer need to monitor MicroB while it's running, and also means that MicroB should behave as it does when browser-switchboard isn't running). Otherwise, we act as before (watch the running MicroB and kill it when the last browser window closes, with the behavior changes this requires). For control freaks, there's also a new autostart_microb config option which allows you to override this heuristic. Setting autostart_microb to 0 forces us to kill MicroB even when MicroB is the configured default browser, and setting it to 1 forces us to leave MicroB running even when MicroB isn't the default. --- diff --git a/README b/README index 2f36e77..7c0217c 100644 --- a/README +++ b/README @@ -78,6 +78,11 @@ default_browser = "tear" #other_browser_cmd = "some_browser %s" # logging: Where log output should go: "stdout", "syslog", "none" #logging = "stdout" +# autostart_microb: Fremantle only: whether MicroB should be +# prestarted in the background: 0 -- never prestart MicroB; 1 -- always +# prestart MicroB; -1 -- only prestart MicroB when MicroB is the default +# browser (default behavior if unset) +#autostart_microb = 0 # END SAMPLE CONFIG FILE Lines beginning with # characters are comments and are ignored by the @@ -118,6 +123,13 @@ run Browser Switchboard from the shell. "syslog" will send the output to the system log (assuming you have a syslogd set up on your device), and "none" disables debug logging entirely. +On Fremantle only, autostart_microb controls whether MicroB is +prestarted when the device boots. By default, MicroB is prestarted only +when MicroB is set as the default browser; you can force MicroB to +always prestart by setting autostart_microb = 1, while you can force it +to never prestart by setting autostart_microb = 0. [This option has no +corresponding UI at the moment.] + Browser Switchboard and MicroB's browserd: diff --git a/browser-switchboard.h b/browser-switchboard.h index 726a553..5f7511f 100644 --- a/browser-switchboard.h +++ b/browser-switchboard.h @@ -27,6 +27,9 @@ struct swb_context { int continuous_mode; void (*default_browser_launcher)(struct swb_context *, char *); char *other_browser_cmd; +#ifdef FREMANTLE + int autostart_microb; +#endif DBusGConnection *session_bus; DBusGProxy *dbus_proxy; }; diff --git a/config.c b/config.c index 8928a3d..033ac0b 100644 --- a/config.c +++ b/config.c @@ -33,6 +33,7 @@ struct swb_config_option swb_config_options[] = { { "default_browser", SWB_CONFIG_OPT_STRING, SWB_CONFIG_DEFAULT_BROWSER_SET }, { "other_browser_cmd", SWB_CONFIG_OPT_STRING, SWB_CONFIG_OTHER_BROWSER_CMD_SET }, { "logging", SWB_CONFIG_OPT_STRING, SWB_CONFIG_LOGGING_SET }, + { "autostart_microb", SWB_CONFIG_OPT_INT, SWB_CONFIG_AUTOSTART_MICROB_SET }, { NULL, 0, 0 }, }; @@ -43,6 +44,7 @@ static struct swb_config swb_config_defaults = { .default_browser = "microb", .other_browser_cmd = NULL, .logging = "stdout", + .autostart_microb = -1, }; @@ -56,6 +58,7 @@ void swb_config_copy(struct swb_config *dst, struct swb_config *src) { dst->entries[1] = &(dst->default_browser); dst->entries[2] = &(dst->other_browser_cmd); dst->entries[3] = &(dst->logging); + dst->entries[4] = &(dst->autostart_microb); dst->flags = src->flags; @@ -63,6 +66,7 @@ void swb_config_copy(struct swb_config *dst, struct swb_config *src) { dst->default_browser = src->default_browser; dst->other_browser_cmd = src->other_browser_cmd; dst->logging = src->logging; + dst->autostart_microb = src->autostart_microb; } /* Initialize a swb_config struct with configuration defaults */ diff --git a/config.h b/config.h index 858aec5..1ca50a3 100644 --- a/config.h +++ b/config.h @@ -28,17 +28,19 @@ #define SWB_CONFIG_DEFAULT_BROWSER_SET 0x04 #define SWB_CONFIG_OTHER_BROWSER_CMD_SET 0x08 #define SWB_CONFIG_LOGGING_SET 0x10 +#define SWB_CONFIG_AUTOSTART_MICROB_SET 0x20 struct swb_config { unsigned int flags; /* Array of pointers to the elements of the struct, in the order given in swb_config_options[] */ - void *entries[4]; + void *entries[5]; int continuous_mode; char *default_browser; char *other_browser_cmd; char *logging; + int autostart_microb; }; struct swb_config_option { diff --git a/launcher.c b/launcher.c index 1b74986..151854e 100644 --- a/launcher.c +++ b/launcher.c @@ -238,6 +238,45 @@ void microb_start_dbus_watch_remove(DBusConnection *conn) { dbus_connection_unref(conn); } +/* Start a new MicroB browser process if one isn't already running */ +pid_t launch_microb_start_browser_process(DBusConnection *conn, int fd) { + pid_t pid; + int status; + + status = system("pidof browser > /dev/null"); + if (WIFEXITED(status) && !WEXITSTATUS(status)) { + /* MicroB browser already running */ + return 0; + } + + if ((pid = fork()) == -1) { + log_perror(errno, "fork"); + return -1; + } + + if (!pid) { + /* Child process */ + dbus_connection_close(conn); + dbus_connection_unref(conn); + if (fd != -1) + close(fd); + close_stdio(); + + /* exec maemo-invoker directly instead of relying on the + /usr/bin/browser symlink, since /usr/bin/browser may have + been replaced with a shell script calling us via D-Bus */ + /* Launch the browser in the background -- our parent will + wait for it to claim the D-Bus name and then display the + window using D-Bus */ + execl("/usr/bin/maemo-invoker", "browser", (char *)NULL); + + /* If we get here, exec() failed */ + exit(1); + } + + return pid; +} + /* Open a MicroB window using the D-Bus interface It's assumed that we have already released the D-Bus name and that it's been ensured that MicroB has acquired com.nokia.osso_browser (otherwise this will @@ -351,29 +390,12 @@ void launch_microb_fremantle_with_kill(struct swb_context *ctx, char *uri) { exit(1); } - if ((pid = fork()) == -1) { - log_perror(errno, "fork"); + /* Launch a MicroB browser process if it's not already running */ + if ((pid = launch_microb_start_browser_process(raw_connection, fd)) < 0) exit(1); - } - if (!pid) { - /* Child process */ - dbus_connection_close(raw_connection); - dbus_connection_unref(raw_connection); - close(fd); - close_stdio(); - - /* exec maemo-invoker directly instead of relying on the - /usr/bin/browser symlink, since /usr/bin/browser may have - been replaced with a shell script calling us via D-Bus */ - /* Launch the browser in the background -- our parent will - wait for it to claim the D-Bus name and then display the - window using D-Bus */ - execl("/usr/bin/maemo-invoker", "browser", (char *)NULL); - - /* If we get here, exec() failed */ - exit(1); - } + /* Release the osso_browser D-Bus name so that MicroB can take it */ + dbus_release_osso_browser_name(ctx); /* Wait for our child to start the browser UI process and for it to acquire the com.nokia.osso_browser D-Bus name, @@ -397,45 +419,55 @@ void launch_microb_fremantle_with_kill(struct swb_context *ctx, char *uri) { that I can think of. Better suggestions would be greatly appreciated. */ - /* Wait for the MicroB browserd lockfile to be created */ - log_msg("Waiting for browserd lockfile to be created\n"); - memset(buf, '\0', 256); - /* read() blocks until there are events to be read */ - while ((bytes_read = read(fd, buf, 255)) > 0) { - pos = buf; - /* Loop until we see the event we're looking for - or until all the events are processed */ - while (pos && (pos-buf) < bytes_read) { - event = (struct inotify_event *)pos; - len = sizeof(struct inotify_event) + event->len; - if (!strcmp(MICROB_LOCKFILE, event->name)) { - /* Lockfile created */ - pos = NULL; + if (!pid) + /* If we didn't start the MicroB browser process ourselves, try + to get the PID of the browserd from the lockfile */ + browserd_pid = get_browserd_pid(microb_lockfile); + else + browserd_pid = 0; + + /* If getting the lockfile PID failed, or the lockfile PID doesn't + exist, assume that we have a stale lockfile and wait for the new + browserd lockfile to be created */ + if (browserd_pid <= 0 || kill(browserd_pid, 0) == ESRCH) { + log_msg("Waiting for browserd lockfile to be created\n"); + memset(buf, '\0', 256); + /* read() blocks until there are events to be read */ + while ((bytes_read = read(fd, buf, 255)) > 0) { + pos = buf; + /* Loop until we see the event we're looking for + or until all the events are processed */ + while (pos && (pos-buf) < bytes_read) { + event = (struct inotify_event *)pos; + len = sizeof(struct inotify_event) + event->len; + if (!strcmp(MICROB_LOCKFILE, event->name)) { + /* Lockfile created */ + pos = NULL; + break; + } else if ((pos-buf) + len < bytes_read) + /* More events to process */ + pos += len; + else + /* All events processed */ + break; + } + if (!pos) + /* Event found, stop looking */ break; - } else if ((pos-buf) + len < bytes_read) - /* More events to process */ - pos += len; + memset(buf, '\0', 256); + } + + if ((browserd_pid = get_browserd_pid(microb_lockfile)) <= 0) { + if (browserd_pid == 0) + log_msg("Profile lockfile link lacks PID\n"); else - /* All events processed */ - break; + log_perror(-browserd_pid, + "readlink() on lockfile failed"); + exit(1); } - if (!pos) - /* Event found, stop looking */ - break; - memset(buf, '\0', 256); } inotify_rm_watch(fd, inot_wd); close(fd); - - /* Get the PID of the browserd from the lockfile */ - if ((browserd_pid = get_browserd_pid(microb_lockfile)) <= 0) { - if (browserd_pid == 0) - log_msg("Profile lockfile link lacks PID\n"); - else - log_perror(-browserd_pid, - "readlink() on lockfile failed"); - exit(1); - } free(microb_lockfile); /* Wait for the browserd to close */ @@ -493,14 +525,53 @@ void launch_microb_fremantle_with_kill(struct swb_context *ctx, char *uri) { started browserd may not close with the UI XXX: Hope we don't cause data loss here! */ log_msg("Killing MicroB\n"); - kill(pid, SIGTERM); - waitpid(pid, &status, 0); + if (pid > 0) { + kill(pid, SIGTERM); + waitpid(pid, &status, 0); + } else { + system("kill `pidof browser` > /dev/null 2>&1"); + } /* Restore old SIGCHLD handler */ if (sigaction(SIGCHLD, &oldact, NULL) == -1) { log_perror(errno, "restoring old SIGCHLD handler failed"); exit(1); } + + dbus_request_osso_browser_name(ctx); +} + +/* Launch a new window in Fremantle MicroB; don't kill the MicroB process + when the session is finished + This is designed to work with a prestarted MicroB process that runs + continuously in the background */ +void launch_microb_fremantle(struct swb_context *ctx, char *uri) { + DBusConnection *raw_connection; + + /* Set up the D-Bus eavesdropping we'll use to watch for MicroB + acquiring the com.nokia.osso_browser D-Bus name */ + if (!(raw_connection = microb_start_dbus_watch_init())) { + exit(1); + } + + /* Launch a MicroB browser process if it's not already running */ + if (launch_microb_start_browser_process(raw_connection, -1) < 0) + exit(1); + + /* Release the osso_browser D-Bus name so that MicroB can take it */ + dbus_release_osso_browser_name(ctx); + + /* Wait for MicroB to acquire com.nokia.osso_browser, then make the + appropriate method call to open the browser window. */ + microb_start_dbus_watch_wait(raw_connection); + microb_start_dbus_watch_remove(raw_connection); + if (!launch_microb_open_window(ctx, uri, + LAUNCH_MICROB_BOOKMARK_WIN_OK)) { + exit(1); + } + + /* Take back the osso_browser D-Bus name from MicroB */ + dbus_request_osso_browser_name(ctx); } #endif /* FREMANTLE */ @@ -527,13 +598,24 @@ void launch_microb(struct swb_context *ctx, char *uri) { #endif } - /* Release the osso_browser D-Bus name so that MicroB can take it */ - dbus_release_osso_browser_name(ctx); - #ifdef FREMANTLE /* Do the insanity to launch Fremantle MicroB */ - launch_microb_fremantle_with_kill(ctx, uri); + if ((ctx->default_browser_launcher == launch_microb && + ctx->autostart_microb) || ctx->autostart_microb == 1) { + + /* If MicroB is set as the default browser, or if the user has + configured MicroB to always be running, just send the + running MicroB the request */ + launch_microb_fremantle(ctx, uri); + } else { + /* Otherwise, launch MicroB and kill it when the user's + MicroB session is done */ + launch_microb_fremantle_with_kill(ctx, uri); + } #else /* !FREMANTLE */ + /* Release the osso_browser D-Bus name so that MicroB can take it */ + dbus_release_osso_browser_name(ctx); + if ((pid = fork()) == -1) { log_perror(errno, "fork"); exit(1); @@ -557,6 +639,8 @@ void launch_microb(struct swb_context *ctx, char *uri) { "browser", "--url", uri, (char *)NULL); } } + + dbus_request_osso_browser_name(ctx); #endif /* FREMANTLE */ /* Kill off browserd if we started it */ @@ -565,8 +649,6 @@ void launch_microb(struct swb_context *ctx, char *uri) { if (!ctx || !ctx->continuous_mode) exit(0); - - dbus_request_osso_browser_name(ctx); } static void launch_other_browser(struct swb_context *ctx, char *uri) { diff --git a/main.c b/main.c index 40823e3..d04ebff 100644 --- a/main.c +++ b/main.c @@ -59,6 +59,9 @@ static void read_config(int signalnum) { } else ctx.other_browser_cmd = NULL; update_default_browser(&ctx, cfg.default_browser); +#ifdef FREMANTLE + ctx.autostart_microb = cfg.autostart_microb; +#endif log_msg("continuous_mode: %d\n", cfg.continuous_mode); log_msg("default_browser: '%s'\n", cfg.default_browser);