Get activities launching with rainbow-0.8.x.

Future extensions:

a) we are now able to reliably detect when an activity's main process has
exited. We should take advantage of this to give better feedback on activity
crashes; e.g. by turning the frame's activity-icon into an error icon and by
inserting the activity's log into the datastore so that it appears in the
Journal.

b) in the future, I'd like rainbow to provide more narrow interfaces for
manipulating jails; e.g. for garbage-collecting them, nuking their contents, or
for reusing them. Please consider this an invitation to show me which interfaces
would work best for Sugar.

P.S. - Thanks to Sascha Silbe for testing and for improvements to this patch.
This commit is contained in:
Michael Stone 2009-02-27 16:42:47 -05:00
parent 6f210f0e33
commit a65c8d2148

View File

@ -34,6 +34,9 @@ from sugar import env
from errno import EEXIST, ENOSPC
import os
import tempfile
import subprocess
import pwd
_SHELL_SERVICE = "org.laptop.Shell"
_SHELL_PATH = "/org/laptop/Shell"
@ -45,10 +48,6 @@ _DS_PATH = "/org/laptop/sugar/DataStore"
_ACTIVITY_FACTORY_INTERFACE = "org.laptop.ActivityFactory"
_RAINBOW_SERVICE_NAME = "org.laptop.security.Rainbow"
_RAINBOW_ACTIVITY_FACTORY_PATH = "/"
_RAINBOW_ACTIVITY_FACTORY_INTERFACE = "org.laptop.security.Rainbow"
# helper method to close all filedescriptors
# borrowed from subprocess.py
try:
@ -253,40 +252,47 @@ class ActivityCreationHandler(gobject.GObject):
self._handle.object_id,
self._handle.uri)
if not self._use_rainbow:
# use gobject spawn functionality, so that zombies are
# automatically reaped by the gobject event loop.
def child_setup():
# clone logfile.fileno() onto stdout/stderr
os.dup2(log_file.fileno(), 1)
os.dup2(log_file.fileno(), 2)
# close all other fds
_close_fds()
# we need to sanitize and str-ize the various bits which
# dbus gives us.
gobject.spawn_async([str(s) for s in command],
envp=['%s=%s' % (k, str(v))
for k, v in environ.items()],
working_directory=str(self._bundle.get_path()),
child_setup=child_setup,
flags=(gobject.SPAWN_SEARCH_PATH |
gobject.SPAWN_LEAVE_DESCRIPTORS_OPEN))
envdir = None
if self._use_rainbow:
envdir = tempfile.mkdtemp()
command = ['/usr/bin/sudo', '-E', '--',
'/usr/bin/rainbow-run',
'-v', '-v',
'-a', '/usr/bin/rainbow-sugarize',
'-s', '/var/spool/rainbow/2',
'-f', '1',
'-f', '2',
'-c', self._bundle.get_path(),
'-u', pwd.getpwuid(os.getuid()).pw_name,
'-i', environ['SUGAR_BUNDLE_ID'],
'-e', envdir,
'--'
] + command
for k, v in environ.items():
open(os.path.join(envdir, str(k)), 'w').write(str(v))
log_file.write(' '.join(command) + '\n\n')
def handler(pid, condition, user_data):
if envdir: subprocess.call(['/bin/rm', '-rf', envdir])
try:
log_file.write('Activity died: pid %s condition %s data %s\n' %
(pid, condition, user_data))
finally:
log_file.close()
else:
log_file.close()
system_bus = dbus.SystemBus()
factory = system_bus.get_object(_RAINBOW_SERVICE_NAME,
_RAINBOW_ACTIVITY_FACTORY_PATH)
factory.CreateActivity(
log_path,
environ,
command,
environ['SUGAR_BUNDLE_PATH'],
environ['SUGAR_BUNDLE_ID'],
timeout=30,
reply_handler=self._create_reply_handler,
error_handler=self._create_error_handler,
dbus_interface=_RAINBOW_ACTIVITY_FACTORY_INTERFACE)
# try to reap zombies in case SIGCHLD has not been set to SIG_IGN
try :
os.waitpid(pid, 0)
except OSError:
# SIGCHLD = SIG_IGN, no zombies
pass
devnull = file("/dev/null", "r")
child = subprocess.Popen([str(s) for s in command], env=environ,
cwd=str(self._bundle.get_path()), close_fds=True,
stdin=devnull.fileno(), stdout=log_file.fileno(),
stderr=log_file.fileno())
gobject.child_watch_add(child.pid, handler, self._handle.activity_id)
def _no_reply_handler(self, *args):
pass