Fremantle: Coexist with a running MicroB process; don't kill MicroB at end of session...
authorSteven Luo <steven+maemo@steven676.net>
Sun, 30 May 2010 07:58:08 +0000 (00:58 -0700)
committerSteven Luo <steven+maemo@steven676.net>
Fri, 27 Aug 2010 10:38:17 +0000 (03:38 -0700)
With commit aeb836f5... ("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.

README
browser-switchboard.h
config.c
config.h
launcher.c
main.c

diff --git a/README b/README
index 2f36e77..7c0217c 100644 (file)
--- 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"
 #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
 # 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.
 
 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:
 
 
 Browser Switchboard and MicroB's browserd:
 
index 3f1cfdd..26f92d8 100644 (file)
@@ -27,6 +27,9 @@ struct swb_context {
        int continuous_mode;
        void (*default_browser_launcher)(struct swb_context *, char *);
        char *other_browser_cmd;
        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;
        DBusGConnection *system_bus;
        DBusGConnection *session_bus;
        DBusGProxy *dbus_proxy;
        DBusGConnection *system_bus;
index 7fe6874..2dcbfae 100644 (file)
--- 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 },
        { "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 },
 };
 
        { NULL, 0, 0 },
 };
 
@@ -43,6 +44,7 @@ static struct swb_config swb_config_defaults = {
        .default_browser = "microb",
        .other_browser_cmd = NULL,
        .logging = "stdout",
        .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[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;
 
 
        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->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 */
 }
 
 /* Initialize a swb_config struct with configuration defaults */
index 858aec5..1ca50a3 100644 (file)
--- a/config.h
+++ b/config.h
 #define SWB_CONFIG_DEFAULT_BROWSER_SET         0x04
 #define SWB_CONFIG_OTHER_BROWSER_CMD_SET       0x08
 #define SWB_CONFIG_LOGGING_SET                 0x10
 #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[] */
 
 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 continuous_mode;
        char *default_browser;
        char *other_browser_cmd;
        char *logging;
+       int autostart_microb;
 };
 
 struct swb_config_option {
 };
 
 struct swb_config_option {
index 72ff490..5a7c773 100644 (file)
@@ -238,6 +238,45 @@ void microb_start_dbus_watch_remove(DBusConnection *conn) {
        dbus_connection_unref(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
 /* 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);
        }
 
                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);
                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,
 
        /* 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. */
 
           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;
                                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
                        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);
        }
        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 */
        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");
           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);
        }
 
        /* 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 */
 
 }
 #endif /* FREMANTLE */
 
@@ -527,13 +598,24 @@ void launch_microb(struct swb_context *ctx, char *uri) {
 #endif
        }
 
 #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 */
 #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 */
 #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);
        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);
                }
        }
                              "browser", "--url", uri, (char *)NULL);
                }
        }
+
+       dbus_request_osso_browser_name(ctx);
 #endif /* FREMANTLE */
 
        /* Kill off browserd if we started it */
 #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);
 
        if (!ctx || !ctx->continuous_mode)
                exit(0);
-
-       dbus_request_osso_browser_name(ctx);
 }
 
 static void launch_other_browser(struct swb_context *ctx, char *uri) {
 }
 
 static void launch_other_browser(struct swb_context *ctx, char *uri) {
diff --git a/main.c b/main.c
index af022c8..2e19b84 100644 (file)
--- a/main.c
+++ b/main.c
@@ -66,6 +66,9 @@ static void read_config(int signalnum) {
        } else
                ctx.other_browser_cmd = NULL;
        update_default_browser(&ctx, cfg.default_browser);
        } 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);
 
        log_msg("continuous_mode: %d\n", cfg.continuous_mode);
        log_msg("default_browser: '%s'\n", cfg.default_browser);