Merge ""core": Make glob-patterns the default"
diff --git a/lib/modules/core/core.go b/lib/modules/core/core.go
index c2919fa..c937287 100644
--- a/lib/modules/core/core.go
+++ b/lib/modules/core/core.go
@@ -47,9 +47,6 @@
 // echoClient <name> <text>
 //    invoke <name>.Echo(<text>)
 //
-// exec <command> [args...]
-//    executes the given command with the given arguments
-//
 // proxyd <names>...
 //    runs a proxy server
 package core
@@ -67,5 +64,4 @@
 	ProxyServerCommand   = "proxyd"
 	WSPRCommand          = "wsprd"
 	TestIdentitydCommand = "test_identityd"
-	ExecCommand          = "exec"
 )
diff --git a/lib/modules/core/core_test.go b/lib/modules/core/core_test.go
index e5071c2..15a7c6a 100644
--- a/lib/modules/core/core_test.go
+++ b/lib/modules/core/core_test.go
@@ -202,7 +202,7 @@
 func TestExec(t *testing.T) {
 	sh, cleanup := newShell(t)
 	defer cleanup()
-	h, err := sh.Start(core.ExecCommand, nil, []string{"/bin/sh", "-c", "echo hello world"}...)
+	h, err := sh.StartExternalCommand(nil, []string{"/bin/sh", "-c", "echo hello world"}...)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -218,7 +218,7 @@
 func TestExecWithEnv(t *testing.T) {
 	sh, cleanup := newShell(t)
 	defer cleanup()
-	h, err := sh.Start(core.ExecCommand, []string{"BLAH=hello world"}, "/bin/sh", "-c", "printenv BLAH")
+	h, err := sh.StartExternalCommand([]string{"BLAH=hello world"}, "/bin/sh", "-c", "printenv BLAH")
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/lib/modules/core/exec.go b/lib/modules/core/exec.go
deleted file mode 100644
index be41d0d..0000000
--- a/lib/modules/core/exec.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package core
-
-import (
-	"io"
-	"syscall"
-
-	"v.io/core/veyron/lib/modules"
-)
-
-func init() {
-	modules.RegisterChild(ExecCommand, "", execCommand)
-}
-
-func execCommand(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
-	envSlice := []string{}
-	for key, value := range env {
-		envSlice = append(envSlice, key+"="+value)
-	}
-	return syscall.Exec(args[1], args[1:], envSlice)
-}
diff --git a/lib/modules/exec.go b/lib/modules/exec.go
index b7e77c0..547ac0d 100644
--- a/lib/modules/exec.go
+++ b/lib/modules/exec.go
@@ -70,6 +70,10 @@
 	return &execHandle{name: name, entryPoint: shellEntryPoint + "=" + name, procErrCh: make(chan error, 1)}
 }
 
+func newExecHandleForExternalCommand(name string) command {
+	return &execHandle{name: name, procErrCh: make(chan error, 1)}
+}
+
 func (eh *execHandle) Stdout() io.Reader {
 	eh.mu.Lock()
 	defer eh.mu.Unlock()
@@ -114,8 +118,16 @@
 	eh.mu.Lock()
 	defer eh.mu.Unlock()
 	eh.sh = sh
-	newargs, newenv := eh.envelope(sh, env, args[1:]...)
-	cmd := exec.Command(os.Args[0], newargs[1:]...)
+	cmdPath := args[0]
+	newargs, newenv := args, env
+
+	// If an entry point is specified, use the envelope execution environment.
+	if eh.entryPoint != "" {
+		cmdPath = os.Args[0]
+		newargs, newenv = eh.envelope(sh, env, args[1:]...)
+	}
+
+	cmd := exec.Command(cmdPath, newargs[1:]...)
 	cmd.Env = newenv
 	stderr, err := newLogfile("stderr", eh.name)
 	if err != nil {
@@ -160,7 +172,6 @@
 		return nil, err
 	}
 	vlog.VI(1).Infof("Started: %q, pid %d", eh.name, cmd.Process.Pid)
-	err = handle.WaitForReady(sh.startTimeout)
 	go func() {
 		eh.procErrCh <- eh.handle.Wait(0)
 		// It's now safe to close eh.stdout, since Wait only returns
@@ -170,7 +181,7 @@
 		eh.stdout.Close()
 	}()
 
-	return eh, err
+	return eh, nil
 }
 
 func (eh *execHandle) Pid() int {
@@ -215,3 +226,7 @@
 
 	return procErr
 }
+
+func (eh *execHandle) WaitForReady(timeout time.Duration) error {
+	return eh.handle.WaitForReady(timeout)
+}
diff --git a/lib/modules/func.go b/lib/modules/func.go
index e7372e6..5c5bc4c 100644
--- a/lib/modules/func.go
+++ b/lib/modules/func.go
@@ -5,6 +5,7 @@
 	"io"
 	"os"
 	"sync"
+	"time"
 
 	"v.io/core/veyron2/vlog"
 )
@@ -143,3 +144,7 @@
 	fh.mu.Unlock()
 	return funcErr
 }
+
+func (fh *functionHandle) WaitForReady(time.Duration) error {
+	return nil
+}
diff --git a/lib/modules/registry.go b/lib/modules/registry.go
index 7b01a1e..8331f9c 100644
--- a/lib/modules/registry.go
+++ b/lib/modules/registry.go
@@ -39,7 +39,7 @@
 	return r.cmds[name]
 }
 
-// RegisterChild adds a new command to the registery that will be run
+// RegisterChild adds a new command to the registry that will be run
 // as a subprocess. It must be called before Dispatch or DispatchInTest is
 // called, typically from an init function.
 func RegisterChild(name, help string, main Main) {
diff --git a/lib/modules/shell.go b/lib/modules/shell.go
index c80aae7..cc14137 100644
--- a/lib/modules/shell.go
+++ b/lib/modules/shell.go
@@ -37,6 +37,7 @@
 package modules
 
 import (
+	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -135,7 +136,7 @@
 	return sh, nil
 }
 
-func (sh *Shell) getChildCredentials() (*os.File, error) {
+func (sh *Shell) getChildCredentials() (c *os.File, err error) {
 	if sh.ctx == nil {
 		return nil, nil
 	}
@@ -145,11 +146,16 @@
 	if err != nil {
 		return nil, err
 	}
+	defer func() {
+		if err != nil {
+			conn.Close()
+		}
+	}()
 	ctx, cancel := context.WithCancel(sh.ctx)
+	defer cancel()
 	if ctx, _, err = veyron2.SetNewStreamManager(ctx); err != nil {
 		return nil, err
 	}
-	defer cancel()
 	syscall.ForkLock.RLock()
 	fd, err := syscall.Dup(int(conn.Fd()))
 	if err != nil {
@@ -160,6 +166,7 @@
 	syscall.ForkLock.RUnlock()
 	p, err := agent.NewAgentPrincipal(ctx, fd, veyron2.GetClient(ctx))
 	if err != nil {
+		syscall.Close(fd)
 		return nil, err
 	}
 	blessingForChild, err := root.Bless(p.PublicKey(), rootBlessing, childBlessingExtension, security.UnconstrainedUse())
@@ -213,6 +220,14 @@
 	return registry.help(command)
 }
 
+func (sh *Shell) StartExternalCommand(env []string, args ...string) (Handle, error) {
+	if len(args) == 0 {
+		return nil, errors.New("no arguments specified to StartExternalCommand")
+	}
+	c := newExecHandleForExternalCommand(args[0])
+	return sh.startCommand(c, env, args...)
+}
+
 // Start starts the specified command, it returns a Handle which can be
 // used for interacting with that command.
 //
@@ -236,6 +251,26 @@
 // Commands must have already been registered using RegisterFunction
 // or RegisterChild.
 func (sh *Shell) Start(name string, env []string, args ...string) (Handle, error) {
+	cmd := registry.getCommand(name)
+	if cmd == nil {
+		return nil, fmt.Errorf("%s: not registered", name)
+	}
+	expanded := append([]string{name}, sh.expand(args...)...)
+	c := cmd.factory()
+	h, err := sh.startCommand(c, env, expanded...)
+	if err != nil {
+		// If the error is a timeout, then h can be used to recover
+		// any output from the process.
+		return h, err
+	}
+
+	if err := h.WaitForReady(sh.waitTimeout); err != nil {
+		return h, err
+	}
+	return h, nil
+}
+
+func (sh *Shell) startCommand(c command, env []string, args ...string) (Handle, error) {
 	cenv, err := sh.setupCommandEnv(env)
 	if err != nil {
 		return nil, err
@@ -244,16 +279,10 @@
 	if err != nil {
 		return nil, err
 	}
-	cmd := registry.getCommand(name)
-	if cmd == nil {
-		return nil, fmt.Errorf("%s: not registered", name)
-	}
-	expanded := append([]string{name}, sh.expand(args...)...)
-	h, err := cmd.factory().start(sh, p, cenv, expanded...)
+
+	h, err := c.start(sh, p, cenv, args...)
 	if err != nil {
-		// If the error is a timeout, then h can be used to recover
-		// any output from the process.
-		return h, err
+		return nil, err
 	}
 	sh.mu.Lock()
 	sh.handles[h] = struct{}{}
@@ -459,6 +488,11 @@
 
 	// Pid returns the pid of the process running the command
 	Pid() int
+
+	// WaitForReady waits until the child process signals to us that it is
+	// ready. If this does not occur within the given timeout duration, a
+	// timeout error is returned.
+	WaitForReady(timeout time.Duration) error
 }
 
 // command is used to abstract the implementations of inprocess and subprocess
diff --git a/lib/stats/sysstats/sysstats.go b/lib/stats/sysstats/sysstats.go
index 75c0c17..9579280 100644
--- a/lib/stats/sysstats/sysstats.go
+++ b/lib/stats/sysstats/sysstats.go
@@ -21,6 +21,7 @@
 	stats.NewInteger("system/num-cpu").Set(int64(runtime.NumCPU()))
 	stats.NewIntegerFunc("system/num-goroutine", func() int64 { return int64(runtime.NumGoroutine()) })
 	stats.NewString("system/version").Set(runtime.Version())
+	stats.NewInteger("system/pid").Set(int64(os.Getpid()))
 	if hostname, err := os.Hostname(); err == nil {
 		stats.NewString("system/hostname").Set(hostname)
 	}
diff --git a/lib/stats/sysstats/sysstats_test.go b/lib/stats/sysstats/sysstats_test.go
index ee2f835..d157b5e 100644
--- a/lib/stats/sysstats/sysstats_test.go
+++ b/lib/stats/sysstats/sysstats_test.go
@@ -31,3 +31,14 @@
 		t.Errorf("unexpected Alloc value. Got %v, want != 0", v)
 	}
 }
+
+func TestPid(t *testing.T) {
+	obj, err := stats.GetStatsObject("system/pid")
+	if err != nil {
+		t.Fatalf("unexpected error: %v", err)
+	}
+	expected := int64(os.Getpid())
+	if got := obj.Value(); got != expected {
+		t.Errorf("unexpected result. Got %q, want %q", got, expected)
+	}
+}
diff --git a/lib/testutil/integration/util.go b/lib/testutil/integration/util.go
index 46a2a6b..208fad1 100644
--- a/lib/testutil/integration/util.go
+++ b/lib/testutil/integration/util.go
@@ -262,9 +262,9 @@
 		locationString = fmt.Sprintf("(requested at %s:%d) ", filepath.Base(file), line)
 	}
 	b.env.t.Logf("%sstarting %s %s", locationString, b.Path(), strings.Join(args, " "))
-	handle, err := b.env.shell.Start("exec", b.envVars, append([]string{b.Path()}, args...)...)
+	handle, err := b.env.shell.StartExternalCommand(b.envVars, append([]string{b.Path()}, args...)...)
 	if err != nil {
-		b.env.t.Fatalf("Start(%v, %v) failed: %v", b.Path(), strings.Join(args, ", "), err)
+		b.env.t.Fatalf("StartExternalCommand(%v, %v) failed: %v", b.Path(), strings.Join(args, ", "), err)
 	}
 	b.env.t.Logf("started PID %d\n", handle.Pid())
 	return &integrationTestBinaryInvocation{
diff --git a/lib/unixfd/unixfd.go b/lib/unixfd/unixfd.go
index fd17a93..fa0fe85 100644
--- a/lib/unixfd/unixfd.go
+++ b/lib/unixfd/unixfd.go
@@ -231,12 +231,16 @@
 	// This is to work around a race on OS X where it appears we can close
 	// the file descriptor before it gets transfered over the socket.
 	f := local.releaseFile()
+	syscall.ForkLock.Lock()
 	fd, err := syscall.Dup(int(f.Fd()))
 	if err != nil {
+		syscall.ForkLock.Unlock()
 		f.Close()
 		rfile.Close()
 		return nil, err
 	}
+	syscall.CloseOnExec(fd)
+	syscall.ForkLock.Unlock()
 	newConn, err := net.FileConn(f)
 	f.Close()
 	if err != nil {
@@ -290,11 +294,15 @@
 		return nil, n, nil, nil
 	}
 	result := Addr(uintptr(fd))
+	syscall.ForkLock.Lock()
 	fd, err = syscall.Dup(fd)
 	if err != nil {
+		syscall.ForkLock.Unlock()
 		CloseUnixAddr(result)
 		return nil, n, nil, err
 	}
+	syscall.CloseOnExec(fd)
+	syscall.ForkLock.Unlock()
 	file := os.NewFile(uintptr(fd), "newconn")
 	newconn, err := net.FileConn(file)
 	file.Close()
diff --git a/profiles/chrome/chromeinit.go b/profiles/chrome/chromeinit.go
index 9f4ace2..1019de9 100644
--- a/profiles/chrome/chromeinit.go
+++ b/profiles/chrome/chromeinit.go
@@ -7,6 +7,7 @@
 
 	"v.io/core/veyron2"
 	"v.io/core/veyron2/context"
+	"v.io/core/veyron2/ipc"
 	"v.io/core/veyron2/ipc/stream"
 	"v.io/core/veyron2/vlog"
 
@@ -31,7 +32,9 @@
 		return nil, nil, nil, err
 	}
 
-	runtime, ctx, shutdown, err := grt.Init(ctx, nil, nil, nil, commonFlags.RuntimeFlags(), nil)
+	protocols := []string{"wsh", "ws"}
+	listenSpec := ipc.ListenSpec{Addrs: ipc.ListenAddrs{{Protocol: "ws", Address: ""}}}
+	runtime, ctx, shutdown, err := grt.Init(ctx, nil, protocols, &listenSpec, commonFlags.RuntimeFlags(), nil)
 	if err != nil {
 		return nil, nil, shutdown, err
 	}
diff --git a/profiles/roaming/roaming_server.go b/profiles/roaming/roaming_server.go
index e85f22e..30874be 100644
--- a/profiles/roaming/roaming_server.go
+++ b/profiles/roaming/roaming_server.go
@@ -7,6 +7,7 @@
 
 	"v.io/core/veyron2"
 	"v.io/core/veyron2/ipc"
+	"v.io/core/veyron2/vlog"
 
 	"v.io/core/veyron/profiles/roaming"
 )
@@ -14,11 +15,10 @@
 func main() {
 	ctx, shutdown := veyron2.Init()
 	defer shutdown()
-	log := veyron2.GetLogger(ctx)
 
 	server, err := veyron2.NewServer(ctx)
 	if err != nil {
-		log.Fatalf("unexpected error: %q", err)
+		vlog.Fatalf("unexpected error: %q", err)
 	}
 
 	listenSpec := veyron2.GetListenSpec(ctx)
@@ -26,13 +26,13 @@
 	fmt.Printf("listen spec: %v\n", listenSpec)
 	ep, err := server.Listen(listenSpec)
 	if err != nil {
-		log.Fatalf("unexpected error: %q", err)
+		vlog.Fatalf("unexpected error: %q", err)
 	}
 	if ep != nil {
 		fmt.Println(ep)
 	}
 	if err := server.Serve("roamer", &receiver{}, nil); err != nil {
-		log.Fatalf("unexpected error: %q", err)
+		vlog.Fatalf("unexpected error: %q", err)
 	}
 
 	done := make(chan struct{})
diff --git a/profiles/roaming/roaminginit.go b/profiles/roaming/roaminginit.go
index 48350e4..45a5f56 100644
--- a/profiles/roaming/roaminginit.go
+++ b/profiles/roaming/roaminginit.go
@@ -139,7 +139,6 @@
 	ch chan<- config.Setting) {
 	defer close(ch)
 
-	log := runtime.GetLogger(ctx)
 	listenSpec := runtime.GetListenSpec(ctx)
 
 	// TODO(cnicolaou): add support for listening on multiple network addresses.
@@ -150,21 +149,21 @@
 		case <-watcher.Channel():
 			cur, err := netstate.GetAccessibleIPs()
 			if err != nil {
-				log.Errorf("failed to read network state: %s", err)
+				vlog.Errorf("failed to read network state: %s", err)
 				continue
 			}
 			removed := netstate.FindRemoved(prev, cur)
 			added := netstate.FindAdded(prev, cur)
-			log.VI(2).Infof("Previous: %d: %s", len(prev), prev)
-			log.VI(2).Infof("Current : %d: %s", len(cur), cur)
-			log.VI(2).Infof("Added   : %d: %s", len(added), added)
-			log.VI(2).Infof("Removed : %d: %s", len(removed), removed)
+			vlog.VI(2).Infof("Previous: %d: %s", len(prev), prev)
+			vlog.VI(2).Infof("Current : %d: %s", len(cur), cur)
+			vlog.VI(2).Infof("Added   : %d: %s", len(added), added)
+			vlog.VI(2).Infof("Removed : %d: %s", len(removed), removed)
 			if len(removed) == 0 && len(added) == 0 {
-				log.VI(2).Infof("Network event that lead to no address changes since our last 'baseline'")
+				vlog.VI(2).Infof("Network event that lead to no address changes since our last 'baseline'")
 				continue
 			}
 			if len(removed) > 0 {
-				log.VI(2).Infof("Sending removed: %s", removed)
+				vlog.VI(2).Infof("Sending removed: %s", removed)
 				ch <- ipc.NewRmAddrsSetting(removed)
 			}
 			// We will always send the best currently available address
diff --git a/runtimes/fake/runtime.go b/runtimes/fake/runtime.go
index baa6386..4f5bd29 100644
--- a/runtimes/fake/runtime.go
+++ b/runtimes/fake/runtime.go
@@ -7,7 +7,6 @@
 	"v.io/core/veyron2"
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/security"
-	"v.io/core/veyron2/vlog"
 
 	tsecurity "v.io/core/veyron/lib/testutil/security"
 )
@@ -28,6 +27,10 @@
 	return &Runtime{}, ctx, func() {}, nil
 }
 
+func (r *Runtime) Init(ctx *context.T) error {
+	return nil
+}
+
 func (r *Runtime) SetPrincipal(ctx *context.T, principal security.Principal) (*context.T, error) {
 	return context.WithValue(ctx, principalKey, principal), nil
 }
@@ -37,19 +40,6 @@
 	return p
 }
 
-func (r *Runtime) SetNewLogger(ctx *context.T, name string, opts ...vlog.LoggingOpts) (*context.T, vlog.Logger, error) {
-	logger, err := vlog.NewLogger(name, opts...)
-	if err != nil {
-		return context.WithValue(ctx, loggerKey, logger), logger, nil
-	}
-	return ctx, nil, err
-}
-
-func (r *Runtime) GetLogger(ctx *context.T) vlog.Logger {
-	l, _ := ctx.Value(loggerKey).(vlog.Logger)
-	return l
-}
-
 func (r *Runtime) GetAppCycle(ctx *context.T) veyron2.AppCycle {
 	panic("unimplemented")
 }
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index de89583..c0d41df 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -79,6 +79,9 @@
 	errAuthNoPatternMatch = verror.Register(pkgPath+".authNoPatternMatch",
 		verror.NoRetry, "server blessings {3} do not match pattern {4}")
 
+	errAuthServerNotAllowed = verror.Register(pkgPath+".authServerNotAllowed",
+		verror.NoRetry, "set of allowed servers {3} not matched by server blessings {4}")
+
 	errDefaultAuthDenied = verror.Register(pkgPath+".defaultAuthDenied", verror.NoRetry, "default authorization precludes talking to server with blessings{:3}")
 
 	errBlessingGrant = verror.Register(pkgPath+".blessingGrantFailed", verror.NoRetry, "failed to grant blessing to server with blessings {3}{:4}")
@@ -122,6 +125,13 @@
 	encrypted bool
 }
 
+// PreferredProtocols instructs the Runtime implementation to select
+// endpoints with the specified protocols and to order them in the
+// specified order.
+type PreferredProtocols []string
+
+func (PreferredProtocols) IPCClientOpt() {}
+
 func InternalNewClient(streamMgr stream.Manager, ns naming.Namespace, opts ...ipc.ClientOpt) (ipc.Client, error) {
 	c := &client{
 		streamMgr: streamMgr,
@@ -135,7 +145,7 @@
 		switch v := opt.(type) {
 		case stream.VCOpt:
 			c.vcOpts = append(c.vcOpts, v)
-		case options.PreferredProtocols:
+		case PreferredProtocols:
 			c.preferredProtocols = v
 		}
 	}
@@ -654,6 +664,17 @@
 	}
 	for _, o := range opts {
 		switch v := o.(type) {
+		case options.AllowedServersPolicy:
+			allowed := false
+			for _, p := range v {
+				if p.MatchedBy(serverBlessings...) {
+					allowed = true
+					break
+				}
+			}
+			if !allowed {
+				return nil, nil, verror.Make(errAuthServerNotAllowed, ctx, v, serverBlessings)
+			}
 		case ipc.Granter:
 			if b, err := v.Grant(flow.RemoteBlessings()); err != nil {
 				return nil, nil, verror.Make(errBlessingGrant, ctx, serverBlessings, err)
diff --git a/runtimes/google/ipc/debug_test.go b/runtimes/google/ipc/debug_test.go
index 7290cd5..547d350 100644
--- a/runtimes/google/ipc/debug_test.go
+++ b/runtimes/google/ipc/debug_test.go
@@ -36,7 +36,7 @@
 	defer sm.Shutdown()
 	ns := tnaming.NewSimpleNamespace()
 	ctx := testContext()
-	server, err := InternalNewServer(ctx, sm, ns, nil, options.ReservedNameDispatcher{debugDisp}, vc.LocalPrincipal{pserver})
+	server, err := InternalNewServer(ctx, sm, ns, nil, ReservedNameDispatcher{debugDisp}, vc.LocalPrincipal{pserver})
 	if err != nil {
 		t.Fatalf("InternalNewServer failed: %v", err)
 	}
diff --git a/runtimes/google/ipc/full_test.go b/runtimes/google/ipc/full_test.go
index 45f3a61..f46b0b7 100644
--- a/runtimes/google/ipc/full_test.go
+++ b/runtimes/google/ipc/full_test.go
@@ -6,7 +6,6 @@
 	"fmt"
 	"io"
 	"net"
-	"os"
 	"path/filepath"
 	"reflect"
 	"runtime"
@@ -352,10 +351,8 @@
 }
 
 func matchesErrorPattern(err error, id verror.IDAction, pattern string) bool {
-	if len(pattern) > 0 && err != nil {
-		if strings.Index(err.Error(), pattern) < 0 {
-			fmt.Fprintf(os.Stderr, "got error msg: %q, expected: %q\n", err, pattern)
-		}
+	if len(pattern) > 0 && err != nil && strings.Index(err.Error(), pattern) < 0 {
+		return false
 	}
 	if err == nil && id.ID == "" {
 		return true
@@ -427,73 +424,91 @@
 
 func TestRPCServerAuthorization(t *testing.T) {
 	const (
-		vcErr   = "VC handshake failed"
-		nameErr = "do not match pattern"
+		vcErr      = "VC handshake failed"
+		nameErr    = "do not match pattern"
+		allowedErr = "set of allowed servers"
 	)
 	var (
 		pprovider, pclient, pserver = tsecurity.NewPrincipal("root"), tsecurity.NewPrincipal(), tsecurity.NewPrincipal()
 		pdischarger                 = pprovider
-
-		now = time.Now()
-
-		serverName          = "mountpoint/server"
-		dischargeServerName = "mountpoint/dischargeserver"
+		now                         = time.Now()
+		noErrID                     verror.IDAction
 
 		// Third-party caveats on blessings presented by server.
-		cavTPValid   = mkThirdPartyCaveat(pdischarger.PublicKey(), dischargeServerName, mkCaveat(security.ExpiryCaveat(now.Add(24*time.Hour))))
-		cavTPExpired = mkThirdPartyCaveat(pdischarger.PublicKey(), dischargeServerName, mkCaveat(security.ExpiryCaveat(now.Add(-1*time.Second))))
+		cavTPValid   = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/dischargeserver", mkCaveat(security.ExpiryCaveat(now.Add(24*time.Hour))))
+		cavTPExpired = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/dischargeserver", mkCaveat(security.ExpiryCaveat(now.Add(-1*time.Second))))
 
 		// Server blessings.
 		bServer          = bless(pprovider, pserver, "server")
 		bServerExpired   = bless(pprovider, pserver, "server", mkCaveat(security.ExpiryCaveat(time.Now().Add(-1*time.Second))))
 		bServerTPValid   = bless(pprovider, pserver, "serverWithTPCaveats", cavTPValid)
 		bServerTPExpired = bless(pprovider, pserver, "serverWithTPCaveats", cavTPExpired)
+		bTwoBlessings, _ = security.UnionOfBlessings(bServer, bServerTPValid)
 
 		mgr   = imanager.InternalNew(naming.FixedRoutingID(0x1111111))
 		ns    = tnaming.NewSimpleNamespace()
 		tests = []struct {
-			server  security.Blessings       // blessings presented by the server to the client.
-			pattern security.BlessingPattern // pattern on the server identity expected by the client.
+			server  security.Blessings           // blessings presented by the server to the client.
+			name    string                       // name provided by the client to StartCall
+			allowed options.AllowedServersPolicy // option provided to StartCall.
 			errID   verror.IDAction
 			err     string
 		}{
-			// Client accepts talking to the server only if the server's blessings match the provided pattern
-			{bServer, security.AllPrincipals, verror.IDAction{}, ""},
-			{bServer, "root/server", verror.IDAction{}, ""},
-			{bServer, "root/otherserver", verror.NotTrusted, nameErr},
-			{bServer, "otherroot/server", verror.NotTrusted, nameErr},
+			// Client accepts talking to the server only if the
+			// server's blessings match the provided pattern
+			{bServer, "mountpoint/server", nil, noErrID, ""},
+			{bServer, "[root/server]mountpoint/server", nil, noErrID, ""},
+			{bServer, "[root/otherserver]mountpoint/server", nil, verror.NotTrusted, nameErr},
+			{bServer, "[otherroot/server]mountpoint/server", nil, verror.NotTrusted, nameErr},
 
-			// and, if the server's blessing has third-party caveats then the server provides
-			// appropriate discharges.
-			{bServerTPValid, security.AllPrincipals, verror.IDAction{}, ""},
-			{bServerTPValid, "root/serverWithTPCaveats", verror.IDAction{}, ""},
-			{bServerTPValid, "root/otherserver", verror.NotTrusted, nameErr},
-			{bServerTPValid, "otherroot/server", verror.NotTrusted, nameErr},
+			// and, if the server's blessing has third-party
+			// caveats then the server provides appropriate
+			// discharges.
+			{bServerTPValid, "mountpoint/server", nil, noErrID, ""},
+			{bServerTPValid, "[root/serverWithTPCaveats]mountpoint/server", nil, noErrID, ""},
+			{bServerTPValid, "[root/otherserver]mountpoint/server", nil, verror.NotTrusted, nameErr},
+			{bServerTPValid, "[otherroot/server]mountpoint/server", nil, verror.NotTrusted, nameErr},
 
-			// Client does not talk to a server that presents expired blessings.
-			{bServerExpired, security.AllPrincipals, verror.NotTrusted, vcErr},
+			// Client does not talk to a server that presents
+			// expired blessings (because the blessing store is
+			// configured to only talk to root/...).
+			{bServerExpired, "mountpoint/server", nil, verror.NotTrusted, vcErr},
 
-			// Client does not talk to a server that fails to provide discharges for
-			// third-party caveats on the blessings presented by it.
-			{bServerTPExpired, security.AllPrincipals, verror.NotTrusted, vcErr},
+			// Client does not talk to a server that fails to
+			// provide discharges for third-party caveats on the
+			// blessings presented by it.
+			{bServerTPExpired, "mountpoint/server", nil, verror.NotTrusted, vcErr},
+
+			// Testing the AllowedServersPolicy option.
+			{bServer, "mountpoint/server", options.AllowedServersPolicy{"otherroot/..."}, verror.NotTrusted, allowedErr},
+			{bServer, "[root/server]mountpoint/server", options.AllowedServersPolicy{"otherroot/..."}, verror.NotTrusted, allowedErr},
+			{bServer, "[otherroot/server]mountpoint/server", options.AllowedServersPolicy{"root/server"}, verror.NotTrusted, nameErr},
+			{bServer, "[root/server]mountpoint/server", options.AllowedServersPolicy{"root/..."}, noErrID, ""},
+			// Server presents two blessings: One that satisfies
+			// the pattern provided to StartCall and one that
+			// satisfies the AllowedServersPolicy, so the server is
+			// authorized.
+			{bTwoBlessings, "[root/serverWithTPCaveats]mountpoint/server", options.AllowedServersPolicy{"root/server"}, noErrID, ""},
 		}
 	)
 
-	_, server := startServer(t, pserver, mgr, ns, serverName, testServerDisp{&testServer{}})
-	defer stopServer(t, server, ns, serverName)
+	_, server := startServer(t, pserver, mgr, ns, "mountpoint/server", testServerDisp{&testServer{}})
+	defer stopServer(t, server, ns, "mountpoint/server")
 
 	// Start the discharge server.
-	_, dischargeServer := startServer(t, pdischarger, mgr, ns, dischargeServerName, testutil.LeafDispatcher(&dischargeServer{}, &acceptAllAuthorizer{}))
-	defer stopServer(t, dischargeServer, ns, dischargeServerName)
+	_, dischargeServer := startServer(t, pdischarger, mgr, ns, "mountpoint/dischargeserver", testutil.LeafDispatcher(&dischargeServer{}, &acceptAllAuthorizer{}))
+	defer stopServer(t, dischargeServer, ns, "mountpoint/dischargeserver")
 
-	// Make the client and server principals trust root certificates from pprovider
+	// Make the client and server principals trust root certificates from
+	// pprovider
 	pclient.AddToRoots(pprovider.BlessingStore().Default())
 	pserver.AddToRoots(pprovider.BlessingStore().Default())
-	// Set a blessing that the client is willing to share with servers with blessings
-	// from pprovider.
+	// Set a blessing that the client is willing to share with servers with
+	// blessings from pprovider.
 	pclient.BlessingStore().Set(bless(pprovider, pclient, "client"), "root/...")
+
 	for i, test := range tests {
-		name := fmt.Sprintf("(%q@%q)", test.pattern, test.server)
+		name := fmt.Sprintf("(Name:%q, Server:%q, Allowed:%v)", test.name, test.server, test.allowed)
 		if err := pserver.BlessingStore().SetDefault(test.server); err != nil {
 			t.Fatalf("SetDefault failed on server's BlessingStore: %v", err)
 		}
@@ -506,9 +521,12 @@
 			t.Errorf("%s: failed to create client: %v", name, err)
 			continue
 		}
-		ctx := testContextWithoutDeadline()
-		dctx, cancel := context.WithTimeout(ctx, 10*time.Second)
-		call, err := client.StartCall(dctx, fmt.Sprintf("[%s]%s/suffix", test.pattern, serverName), "Method", nil)
+		ctx, cancel := context.WithTimeout(testContextWithoutDeadline(), 10*time.Second)
+		var opts []ipc.CallOpt
+		if test.allowed != nil {
+			opts = append(opts, test.allowed)
+		}
+		call, err := client.StartCall(ctx, test.name, "Method", nil, opts...)
 		if !matchesErrorPattern(err, test.errID, test.err) {
 			t.Errorf(`%d: %s: client.StartCall: got error "%v", want to match "%v"`, i, name, err, test.err)
 		} else if call != nil {
@@ -516,8 +534,12 @@
 			if proof == nil {
 				t.Errorf("%s: Returned nil for remote blessings", name)
 			}
-			if !test.pattern.MatchedBy(blessings...) {
-				t.Errorf("%s: %q.MatchedBy(%v) failed", name, test.pattern, blessings)
+			// Currently all tests are configured so that the only
+			// blessings presented by the server that are
+			// recognized by the client match the pattern
+			// "root/..."
+			if len(blessings) < 1 || !security.BlessingPattern("root/...").MatchedBy(blessings...) {
+				t.Errorf("%s: Client sees server as %v, expected a single blessing matching root/...", name, blessings)
 			}
 		}
 		cancel()
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index 26fd9f0..12eeba0 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -138,6 +138,14 @@
 
 func (PreferredServerResolveProtocols) IPCServerOpt() {}
 
+// ReservedNameDispatcher specifies the dispatcher that controls access
+// to framework managed portion of the namespace.
+type ReservedNameDispatcher struct {
+	Dispatcher ipc.Dispatcher
+}
+
+func (ReservedNameDispatcher) IPCServerOpt() {}
+
 func InternalNewServer(ctx *context.T, streamMgr stream.Manager, ns naming.Namespace, opts ...ipc.ServerOpt) (ipc.Server, error) {
 	ctx, _ = vtrace.SetNewSpan(ctx, "NewServer")
 	statsPrefix := naming.Join("ipc", "server", "routing-id", streamMgr.RoutingID().String())
@@ -170,7 +178,7 @@
 			}
 		case options.ServesMountTable:
 			s.servesMountTable = bool(opt)
-		case options.ReservedNameDispatcher:
+		case ReservedNameDispatcher:
 			s.dispReserved = opt.Dispatcher
 		case PreferredServerResolveProtocols:
 			s.preferredProtocols = []string(opt)
diff --git a/runtimes/google/ipc/server_test.go b/runtimes/google/ipc/server_test.go
index 14548b3..8502416 100644
--- a/runtimes/google/ipc/server_test.go
+++ b/runtimes/google/ipc/server_test.go
@@ -408,10 +408,19 @@
 	if err := <-progress; err != nil {
 		t.Fatalf(err.Error())
 	}
-	// Now that the the RPC is done the server should be able to stop.
-	status = server.Status()
-	if got, want := status.State, ipc.ServerStopped; got != want {
-		t.Fatalf("got %s, want %s", got, want)
+
+	// Now that the RPC is done, the server should be able to stop.
+	then = time.Now()
+	for {
+		status = server.Status()
+		if got, want := status.State, ipc.ServerStopped; got != want {
+			if time.Now().Sub(then) > time.Minute {
+				t.Fatalf("got %s, want %s", got, want)
+			}
+		} else {
+			break
+		}
+		time.Sleep(100 * time.Millisecond)
 	}
 }
 
diff --git a/runtimes/google/rt/mgmt.go b/runtimes/google/rt/mgmt.go
index ca0f7e3..ccaad62 100644
--- a/runtimes/google/rt/mgmt.go
+++ b/runtimes/google/rt/mgmt.go
@@ -14,13 +14,17 @@
 	"v.io/core/veyron/lib/exec"
 )
 
-func (rt *Runtime) initMgmt(ctx *context.T, appCycle veyron2.AppCycle, handle *exec.ChildHandle) error {
-	// Do not initialize the mgmt runtime if the process has not
-	// been started through the veyron exec library by a device
-	// manager.
-	if handle == nil {
+func (rt *Runtime) initMgmt(ctx *context.T) error {
+	handle, err := exec.GetChildHandle()
+	if err == exec.ErrNoVersion {
+		// Do not initialize the mgmt runtime if the process has not
+		// been started through the veyron exec library by a device
+		// manager.
 		return nil
+	} else if err != nil {
+		return err
 	}
+
 	parentName, err := handle.Config.Get(mgmt.ParentNameConfigKey)
 	if err != nil {
 		return nil
@@ -45,7 +49,7 @@
 	if err != nil {
 		return err
 	}
-	if err := server.Serve("", appCycle.Remote(), nil); err != nil {
+	if err := server.Serve("", veyron2.GetAppCycle(ctx).Remote(), nil); err != nil {
 		server.Stop()
 		return err
 	}
@@ -55,6 +59,13 @@
 		return err
 	}
 
+	// Note(mattr): that we ignore the error here.
+	// As far as I can tell this is because the modules framework actually calls
+	// SetReady(), so we would then call it here a second time and get
+	// an error.
+	// TODO(mattr): We should change the modules framework so we can properly check
+	// errors here.
+	handle.SetReady()
 	return nil
 }
 
@@ -79,7 +90,7 @@
 
 func (rt *Runtime) callbackToParent(ctx *context.T, parentName, myName string) error {
 	ctx, _ = context.WithTimeout(ctx, time.Minute)
-	call, err := rt.GetClient(ctx).StartCall(ctx, parentName, "Set", []interface{}{mgmt.AppCycleManagerConfigKey, myName}, options.NoResolve{})
+	call, err := rt.GetClient(ctx).StartCall(ctx, parentName, "Set", []interface{}{mgmt.AppCycleManagerConfigKey, myName})
 
 	if err != nil {
 		return err
diff --git a/runtimes/google/rt/rt_test.go b/runtimes/google/rt/rt_test.go
index ce3a6a4..a4e473d 100644
--- a/runtimes/google/rt/rt_test.go
+++ b/runtimes/google/rt/rt_test.go
@@ -36,7 +36,7 @@
 	ctx, shutdown := veyron2.Init()
 	defer shutdown()
 
-	l := veyron2.GetLogger(ctx)
+	l := vlog.Log
 	fmt.Println(l)
 	args := fmt.Sprintf("%s", l)
 	expected := regexp.MustCompile("name=veyron logdirs=\\[/tmp\\] logtostderr=true|false alsologtostderr=false|true max_stack_buf_size=4292608 v=[0-9] stderrthreshold=2 vmodule= log_backtrace_at=:0")
@@ -59,10 +59,10 @@
 }
 
 func child(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
-	ctx, shutdown := veyron2.Init()
+	_, shutdown := veyron2.Init()
 	defer shutdown()
 
-	logger := veyron2.GetLogger(ctx)
+	logger := vlog.Log
 	vlog.Infof("%s\n", logger)
 	fmt.Fprintf(stdout, "%s\n", logger)
 	modules.WaitForEOF(stdin)
diff --git a/runtimes/google/rt/runtime.go b/runtimes/google/rt/runtime.go
index b74bc10..4a5d3da 100644
--- a/runtimes/google/rt/runtime.go
+++ b/runtimes/google/rt/runtime.go
@@ -15,13 +15,11 @@
 	"v.io/core/veyron2/ipc"
 	"v.io/core/veyron2/ipc/stream"
 	"v.io/core/veyron2/naming"
-	"v.io/core/veyron2/options"
 	"v.io/core/veyron2/security"
 	"v.io/core/veyron2/verror2"
 	"v.io/core/veyron2/vlog"
 	"v.io/core/veyron2/vtrace"
 
-	"v.io/core/veyron/lib/exec"
 	"v.io/core/veyron/lib/flags"
 	_ "v.io/core/veyron/lib/stats/sysstats"
 	iipc "v.io/core/veyron/runtimes/google/ipc"
@@ -39,7 +37,6 @@
 	streamManagerKey = contextKey(iota)
 	clientKey
 	namespaceKey
-	loggerKey
 	principalKey
 	reservedNameKey
 	profileKey
@@ -63,26 +60,16 @@
 	opts       []ipc.ServerOpt
 }
 
-// TODO(mattr,suharshs): Decide if ROpts would be better than this.
+// TODO(mattr,suharshs): Decide if Options would be better than this.
 func Init(ctx *context.T, appCycle veyron2.AppCycle, protocols []string, listenSpec *ipc.ListenSpec, flags flags.RuntimeFlags,
 	reservedDispatcher ipc.Dispatcher, dispatcherOpts ...ipc.ServerOpt) (*Runtime, *context.T, veyron2.Shutdown, error) {
 	r := &Runtime{deps: dependency.NewGraph()}
 
-	handle, err := exec.GetChildHandle()
-	switch err {
-	case exec.ErrNoVersion:
-		// The process has not been started through the veyron exec
-		// library. No further action is needed.
-	case nil:
-		// The process has been started through the veyron exec
-		// library.
-	default:
+	err := vlog.ConfigureLibraryLoggerFromFlags()
+	if err != nil {
 		return nil, nil, nil, err
 	}
 
-	r.initLogging(ctx)
-	ctx = context.WithValue(ctx, loggerKey, vlog.Log)
-
 	// Setup the initial trace.
 	ctx, err = ivtrace.Init(ctx, flags.Vtrace)
 	if err != nil {
@@ -148,7 +135,7 @@
 	}
 
 	// Initialize security.
-	principal, err := initSecurity(ctx, handle, flags.Credentials, client)
+	principal, err := initSecurity(ctx, flags.Credentials, client)
 	if err != nil {
 		return nil, nil, nil, err
 	}
@@ -160,20 +147,11 @@
 		return nil, nil, nil, err
 	}
 
-	// Initialize management.
-	if err := r.initMgmt(ctx, r.GetAppCycle(ctx), handle); err != nil {
-		return nil, nil, nil, err
-	}
-
 	ctx = r.SetBackgroundContext(ctx)
 
 	// TODO(suharshs,mattr): Go through the rt.Cleanup function and make sure everything
 	// gets cleaned up.
 
-	if handle != nil {
-		handle.SetReady()
-	}
-
 	return r, ctx, r.shutdown, nil
 }
 
@@ -192,17 +170,15 @@
 	return nil
 }
 
+func (r *Runtime) Init(ctx *context.T) error {
+	return r.initMgmt(ctx)
+}
+
 func (r *Runtime) shutdown() {
 	r.deps.CloseAndWaitForAll()
 	vlog.FlushLog()
 }
 
-// initLogging configures logging for the runtime. It needs to be called after
-// flag.Parse and after signal handling has been initialized.
-func (r *Runtime) initLogging(ctx *context.T) error {
-	return vlog.ConfigureLibraryLoggerFromFlags()
-}
-
 func (r *Runtime) initSignalHandling(ctx *context.T) {
 	// TODO(caprita): Given that our device manager implementation is to
 	// kill all child apps when the device manager dies, we should
@@ -246,7 +222,7 @@
 	otherOpts := append([]ipc.ServerOpt{}, opts...)
 	otherOpts = append(otherOpts, vc.LocalPrincipal{principal})
 	if reserved, ok := ctx.Value(reservedNameKey).(*reservedNameDispatcher); ok {
-		otherOpts = append(otherOpts, options.ReservedNameDispatcher{reserved.dispatcher})
+		otherOpts = append(otherOpts, iipc.ReservedNameDispatcher{reserved.dispatcher})
 		otherOpts = append(otherOpts, reserved.opts...)
 	}
 	if protocols, ok := ctx.Value(protocolsKey).([]string); ok {
@@ -346,7 +322,7 @@
 	otherOpts = append(otherOpts, vc.LocalPrincipal{p}, &imanager.DialTimeout{5 * time.Minute})
 
 	if protocols, ok := ctx.Value(protocolsKey).([]string); ok {
-		otherOpts = append(otherOpts, options.PreferredProtocols(protocols))
+		otherOpts = append(otherOpts, iipc.PreferredProtocols(protocols))
 	}
 
 	client, err := iipc.InternalNewClient(sm, ns, otherOpts...)
@@ -394,19 +370,6 @@
 	return ns
 }
 
-func (*Runtime) SetNewLogger(ctx *context.T, name string, opts ...vlog.LoggingOpts) (*context.T, vlog.Logger, error) {
-	logger, err := vlog.NewLogger(name, opts...)
-	if err == nil {
-		ctx = context.WithValue(ctx, loggerKey, logger)
-	}
-	return ctx, logger, err
-}
-
-func (*Runtime) GetLogger(ctx *context.T) vlog.Logger {
-	logger, _ := ctx.Value(loggerKey).(vlog.Logger)
-	return logger
-}
-
 func (*Runtime) GetAppCycle(ctx *context.T) veyron2.AppCycle {
 	appCycle, _ := ctx.Value(appCycleKey).(veyron2.AppCycle)
 	return appCycle
diff --git a/runtimes/google/rt/security.go b/runtimes/google/rt/security.go
index ab640df..b4a3aef 100644
--- a/runtimes/google/rt/security.go
+++ b/runtimes/google/rt/security.go
@@ -18,8 +18,8 @@
 	"v.io/core/veyron/security/agent"
 )
 
-func initSecurity(ctx *context.T, handle *exec.ChildHandle, credentials string, client ipc.Client) (security.Principal, error) {
-	principal, err := setupPrincipal(ctx, handle, credentials, client)
+func initSecurity(ctx *context.T, credentials string, client ipc.Client) (security.Principal, error) {
+	principal, err := setupPrincipal(ctx, credentials, client)
 	if err != nil {
 		return nil, err
 	}
@@ -31,13 +31,13 @@
 	return principal, nil
 }
 
-func setupPrincipal(ctx *context.T, handle *exec.ChildHandle, credentials string, client ipc.Client) (security.Principal, error) {
+func setupPrincipal(ctx *context.T, credentials string, client ipc.Client) (security.Principal, error) {
 	var err error
 	var principal security.Principal
 	if principal, _ = ctx.Value(principalKey).(security.Principal); principal != nil {
 		return principal, nil
 	}
-	if fd, err := agentFD(handle); err != nil {
+	if fd, err := agentFD(); err != nil {
 		return nil, err
 	} else if fd >= 0 {
 		return connectToAgent(ctx, fd, client)
@@ -66,7 +66,11 @@
 // agentFD returns a non-negative file descriptor to be used to communicate with
 // the security agent if the current process has been configured to use the
 // agent.
-func agentFD(handle *exec.ChildHandle) (int, error) {
+func agentFD() (int, error) {
+	handle, err := exec.GetChildHandle()
+	if err != nil && err != exec.ErrNoVersion {
+		return -1, err
+	}
 	var fd string
 	if handle != nil {
 		// We were started by a parent (presumably, device manager).
diff --git a/security/agent/agentd/main.go b/security/agent/agentd/main.go
index c011d8a..ec7babd 100644
--- a/security/agent/agentd/main.go
+++ b/security/agent/agentd/main.go
@@ -81,13 +81,11 @@
 		vlog.Panic("failed to set principal for ctx: %v", err)
 	}
 
-	log := veyron2.GetLogger(ctx)
-
 	if err = os.Setenv(agent.FdVarName, "3"); err != nil {
-		log.Fatalf("setenv: %v", err)
+		vlog.Fatalf("setenv: %v", err)
 	}
 	if err = os.Setenv(consts.VeyronCredentials, ""); err != nil {
-		log.Fatalf("setenv: %v", err)
+		vlog.Fatalf("setenv: %v", err)
 	}
 
 	if *keypath == "" && passphrase != nil {
@@ -101,11 +99,11 @@
 	// Start running our server.
 	var sock, mgrSock *os.File
 	if sock, err = server.RunAnonymousAgent(ctx, p); err != nil {
-		log.Fatalf("RunAnonymousAgent: %v", err)
+		vlog.Fatalf("RunAnonymousAgent: %v", err)
 	}
 	if *keypath != "" {
 		if mgrSock, err = server.RunKeyManager(ctx, *keypath, passphrase); err != nil {
-			log.Fatalf("RunKeyManager: %v", err)
+			vlog.Fatalf("RunKeyManager: %v", err)
 		}
 	}
 
@@ -123,7 +121,7 @@
 
 		err = cmd.Start()
 		if err != nil {
-			log.Fatalf("Error starting child: %v", err)
+			vlog.Fatalf("Error starting child: %v", err)
 		}
 		shutdown := make(chan struct{})
 		go func() {
diff --git a/security/agent/client.go b/security/agent/client.go
index f3128f9..77c6dde 100644
--- a/security/agent/client.go
+++ b/security/agent/client.go
@@ -57,7 +57,8 @@
 // NewAgentPrincipal returns a security.Pricipal using the PrivateKey held in a remote agent process.
 // 'fd' is the socket for connecting to the agent, typically obtained from
 // os.GetEnv(agent.FdVarName).
-// 'ctx' should not have a deadline, and should never be cancelled.
+// 'ctx' should not have a deadline, and should never be cancelled while the
+// principal is in use.
 func NewAgentPrincipal(ctx *context.T, fd int, insecureClient ipc.Client) (security.Principal, error) {
 	f := os.NewFile(uintptr(fd), "agent_client")
 	defer f.Close()
diff --git a/security/agent/pingpong/main.go b/security/agent/pingpong/main.go
index 532edd9..4b8c428 100644
--- a/security/agent/pingpong/main.go
+++ b/security/agent/pingpong/main.go
@@ -8,6 +8,7 @@
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/ipc"
 	"v.io/core/veyron2/security"
+	"v.io/core/veyron2/vlog"
 
 	"v.io/core/veyron/lib/signals"
 	_ "v.io/core/veyron/profiles"
@@ -22,24 +23,22 @@
 }
 
 func clientMain(ctx *context.T) {
-	log := veyron2.GetLogger(ctx)
-	log.Info("Pinging...")
+	vlog.Info("Pinging...")
 
 	s := PingPongClient("pingpong")
 	pong, err := s.Ping(ctx, "ping")
 	if err != nil {
-		log.Fatal("error pinging: ", err)
+		vlog.Fatal("error pinging: ", err)
 	}
 	fmt.Println(pong)
 }
 
 func serverMain(ctx *context.T) {
-	log := veyron2.GetLogger(ctx)
 	s, err := veyron2.NewServer(ctx)
 	if err != nil {
-		log.Fatal("failure creating server: ", err)
+		vlog.Fatal("failure creating server: ", err)
 	}
-	log.Info("Waiting for ping")
+	vlog.Info("Waiting for ping")
 
 	serverPong := PingPongServer(&pongd{})
 
@@ -47,11 +46,11 @@
 	if endpoint, err := s.Listen(spec); err == nil {
 		fmt.Printf("Listening at: %v\n", endpoint)
 	} else {
-		log.Fatal("error listening to service: ", err)
+		vlog.Fatal("error listening to service: ", err)
 	}
 
 	if err := s.Serve("pingpong", serverPong, allowEveryone{}); err != nil {
-		log.Fatal("error serving service: ", err)
+		vlog.Fatal("error serving service: ", err)
 	}
 
 	// Wait forever.
@@ -63,8 +62,6 @@
 func (allowEveryone) Authorize(security.Context) error { return nil }
 
 func main() {
-	flag.Parse()
-
 	ctx, shutdown := veyron2.Init()
 	defer shutdown()
 
diff --git a/services/mgmt/device/deviced/commands.go b/services/mgmt/device/deviced/commands.go
index 90372cc..aeb3b5b 100644
--- a/services/mgmt/device/deviced/commands.go
+++ b/services/mgmt/device/deviced/commands.go
@@ -16,6 +16,7 @@
 	suidHelper  string
 	agent       string
 	initHelper  string
+	origin      string
 	singleUser  bool
 	sessionMode bool
 	initMode    bool
@@ -50,6 +51,7 @@
 	cmdInstall.Flags.StringVar(&suidHelper, "suid_helper", "", "path to suid helper")
 	cmdInstall.Flags.StringVar(&agent, "agent", "", "path to security agent")
 	cmdInstall.Flags.StringVar(&initHelper, "init_helper", "", "path to sysinit helper")
+	cmdInstall.Flags.StringVar(&origin, "origin", "", "if specified, self-updates will use this origin")
 	cmdInstall.Flags.BoolVar(&singleUser, "single_user", false, "if set, performs the installation assuming a single-user system")
 	cmdInstall.Flags.BoolVar(&sessionMode, "session_mode", false, "if set, installs the device manager to run a single session. Otherwise, the device manager is configured to get restarted upon exit")
 	cmdInstall.Flags.BoolVar(&initMode, "init_mode", false, "if set, installs the device manager with the system init service manager")
@@ -73,7 +75,7 @@
 	if initMode && initHelper == "" {
 		return cmd.UsageErrorf("--init_helper must be set")
 	}
-	if err := impl.SelfInstall(installationDir(), suidHelper, agent, initHelper, singleUser, sessionMode, initMode, args, os.Environ(), cmd.Stderr(), cmd.Stdout()); err != nil {
+	if err := impl.SelfInstall(installationDir(), suidHelper, agent, initHelper, origin, singleUser, sessionMode, initMode, args, os.Environ(), cmd.Stderr(), cmd.Stdout()); err != nil {
 		vlog.Errorf("SelfInstall failed: %v", err)
 		return err
 	}
diff --git a/services/mgmt/device/impl/app_service.go b/services/mgmt/device/impl/app_service.go
index 940df40..2d40769 100644
--- a/services/mgmt/device/impl/app_service.go
+++ b/services/mgmt/device/impl/app_service.go
@@ -108,6 +108,7 @@
 // refine that later.
 
 import (
+	"bytes"
 	"crypto/md5"
 	"crypto/rand"
 	"encoding/base64"
@@ -119,13 +120,12 @@
 	"io/ioutil"
 	"os"
 	"os/exec"
-	"os/user"
 	"path"
 	"path/filepath"
 	"reflect"
 	"strconv"
 	"strings"
-	"sync"
+	"text/template"
 	"time"
 
 	"v.io/core/veyron2"
@@ -190,12 +190,6 @@
 type securityAgentState struct {
 	// Security agent key manager client.
 	keyMgrAgent *keymgr.Agent
-	// Ensures only one security agent connection socket is created
-	// at any time, preventing fork/exec from potentially passing
-	// down sockets meant for other children (as per ribrdb@, Go's
-	// exec implementation does not prune the set of files passed
-	// down to only include those specified in cmd.ExtraFiles).
-	startLock sync.Mutex
 }
 
 // appService implements the Device manager's Application interface.
@@ -473,6 +467,29 @@
 	return installationDir, nil
 }
 
+// agentPrincipal creates a Principal backed by the given agent connection,
+// taking ownership of the connection.  The returned cancel function is to be
+// called when the Principal is no longer in use.
+func agentPrincipal(ctx *context.T, conn *os.File) (security.Principal, func(), error) {
+	agentctx, cancel := context.WithCancel(ctx)
+	var err error
+	if agentctx, _, err = veyron2.SetNewStreamManager(agentctx); err != nil {
+		cancel()
+		conn.Close()
+		return nil, nil, err
+	}
+	p, err := agent.NewAgentPrincipal(agentctx, int(conn.Fd()), veyron2.GetClient(agentctx))
+	if err != nil {
+		cancel()
+		conn.Close()
+		return nil, nil, err
+	}
+	// conn will be closed when the connection to the agent is shut down, as
+	// a result of cancel shutting down the stream manager.  No need to
+	// explicitly call conn.Close() with cancel.
+	return p, cancel, nil
+}
+
 // setupPrincipal sets up the instance's principal, with the right blessings.
 func setupPrincipal(ctx *context.T, instanceDir, versionDir string, call ipc.ServerContext, securityAgent *securityAgentState, info *instanceInfo) error {
 	var p security.Principal
@@ -484,14 +501,16 @@
 			vlog.Errorf("NewPrincipal() failed %v", err)
 			return verror2.Make(ErrOperationFailed, nil)
 		}
-		defer conn.Close()
-
-		// TODO(caprita): release the socket created by NewAgentPrincipal.
-		if p, err = agent.NewAgentPrincipal(ctx, int(conn.Fd()), veyron2.GetClient(ctx)); err != nil {
-			vlog.Errorf("NewAgentPrincipal() failed: %v", err)
+		var cancel func()
+		if p, cancel, err = agentPrincipal(ctx, conn); err != nil {
+			vlog.Errorf("agentPrincipal failed: %v", err)
 			return verror2.Make(ErrOperationFailed, nil)
 		}
+		defer cancel()
 		info.SecurityAgentHandle = handle
+		// conn will be closed when the connection to the agent is shut
+		// down, as a result of cancel() shutting down the stream
+		// manager.  No need to call conn.Close().
 	} else {
 		credentialsDir := filepath.Join(instanceDir, "credentials")
 		// TODO(caprita): The app's system user id needs access to this dir.
@@ -677,56 +696,6 @@
 	return instanceDir, instanceID, nil
 }
 
-// isSetuid is defined like this so we can override its
-// implementation for tests.
-var isSetuid = func(fileStat os.FileInfo) bool {
-	vlog.VI(2).Infof("running the original isSetuid")
-	return fileStat.Mode()&os.ModeSetuid == os.ModeSetuid
-}
-
-// systemAccountForHelper returns the uname that the helper uses to invoke the
-// application. If the helper exists and is setuid, the device manager
-// requires that there is a uname associated with the Veyron
-// identity that requested starting an application.
-// TODO(rjkroege): This function assumes a desktop installation target
-// and is probably not a good fit in other contexts. Revisit the design
-// as appropriate. This function also internalizes a decision as to when
-// it is possible to start an application that needs to be made explicit.
-func systemAccountForHelper(ctx ipc.ServerContext, helperPath string, uat BlessingSystemAssociationStore) (systemName string, err error) {
-	identityNames := ctx.RemoteBlessings().ForContext(ctx)
-	helperStat, err := os.Stat(helperPath)
-	if err != nil {
-		vlog.Errorf("Stat(%v) failed: %v. helper is required.", helperPath, err)
-		return "", verror2.Make(ErrOperationFailed, ctx.Context())
-	}
-	haveHelper := isSetuid(helperStat)
-	systemName, present := uat.SystemAccountForBlessings(identityNames)
-
-	switch {
-	case haveHelper && present:
-		return systemName, nil
-	case haveHelper && !present:
-		// The helper is owned by the device manager and installed as
-		// setuid root.  Therefore, the device manager must never run an
-		// app as itself to prevent an app trivially granting itself
-		// root permissions.  There must be an associated uname for the
-		// account in this case.
-		return "", verror2.Make(verror2.NoAccess, ctx.Context(), "use of setuid helper requires an associated uname.")
-	case !haveHelper:
-		// When the helper is not setuid, the helper can't change the
-		// app's uid so just run the app as the device manager's uname
-		// whether or not there is an association.
-		vlog.VI(1).Infof("helper not setuid. Device manager will invoke app with its own userid")
-		user, err := user.Current()
-		if err != nil {
-			vlog.Errorf("user.Current() failed: %v", err)
-			return "", verror2.Make(ErrOperationFailed, ctx.Context())
-		}
-		return user.Username, nil
-	}
-	return "", verror2.Make(ErrOperationFailed, ctx.Context())
-}
-
 func genCmd(instanceDir, helperPath, systemName string, nsRoots []string) (*exec.Cmd, error) {
 	versionLink := filepath.Join(instanceDir, "version")
 	versionDir, err := filepath.EvalSymlinks(versionLink)
@@ -745,7 +714,15 @@
 	}
 
 	cmd := exec.Command(helperPath)
-	cmd.Args = append(cmd.Args, "--username", systemName)
+
+	switch yes, err := suidHelper.suidhelperEnabled(systemName, helperPath); {
+	case err != nil:
+		return nil, err
+	case yes:
+		cmd.Args = append(cmd.Args, "--username", systemName)
+	case !yes:
+		cmd.Args = append(cmd.Args, "--username", systemName, "--dryrun")
+	}
 
 	var nsRootEnvs []string
 	for i, r := range nsRoots {
@@ -814,24 +791,16 @@
 	cfg.Set(mgmt.ParentBlessingConfigKey, info.DeviceManagerPeerPattern)
 
 	// Set up any agent-specific state.
-	// NOTE(caprita): This ought to belong in genCmd, but we do it here
-	// to avoid holding on to the lock for too long.
-	//
-	// TODO(caprita): We need to take care to grab/release the lock
-	// excluding concurrent start operations.  See if we can make this more
-	// robust.
+	// NOTE(caprita): This ought to belong in genCmd.
 	var agentCleaner func()
 	if sa := i.securityAgent; sa != nil {
-		sa.startLock.Lock()
 		file, err := sa.keyMgrAgent.NewConnection(info.SecurityAgentHandle)
 		if err != nil {
-			sa.startLock.Unlock()
 			vlog.Errorf("NewConnection(%v) failed: %v", info.SecurityAgentHandle, err)
 			return err
 		}
 		agentCleaner = func() {
 			file.Close()
-			sa.startLock.Unlock()
 		}
 		// We need to account for the file descriptors corresponding to
 		// std{err|out|in} as well as the implementation-specific pipes
@@ -908,12 +877,7 @@
 		return nil, err
 	}
 
-	systemName, err := systemAccountForHelper(call, helper, i.uat)
-	if err != nil {
-		cleanupDir(instanceDir, helper)
-		return nil, err
-	}
-
+	systemName := suidHelper.usernameForPrincipal(call, i.uat)
 	if err := saveSystemNameForInstance(instanceDir, systemName); err != nil {
 		cleanupDir(instanceDir, helper)
 		return nil, err
@@ -956,11 +920,7 @@
 		return err
 	}
 
-	systemName, err := systemAccountForHelper(call, i.config.Helper, i.uat)
-	if err != nil {
-		return err
-	}
-
+	systemName := suidHelper.usernameForPrincipal(call, i.uat)
 	startSystemName, err := readSystemNameForInstance(instanceDir)
 	if err != nil {
 		return err
@@ -1306,3 +1266,142 @@
 	}
 	return i.locks.GetPathACL(ctx.LocalPrincipal(), path.Join(dir, "acls"))
 }
+
+func (i *appService) Debug(ctx ipc.ServerContext) (string, error) {
+	switch len(i.suffix) {
+	case 2:
+		return i.installationDebug(ctx)
+	case 3:
+		return i.instanceDebug(ctx)
+	default:
+		return "", verror2.Make(ErrInvalidSuffix, nil)
+	}
+}
+
+func (i *appService) installationDebug(ctx ipc.ServerContext) (string, error) {
+	const installationDebug = `Installation dir: {{.InstallationDir}}
+
+Origin: {{.Origin}}
+
+Envelope: {{printf "%+v" .Envelope}}
+
+Config: {{printf "%+v" .Config}}
+`
+	installationDebugTemplate, err := template.New("installation-debug").Parse(installationDebug)
+	if err != nil {
+		return "", err
+	}
+
+	installationDir, err := i.installationDir()
+	if err != nil {
+		return "", err
+	}
+	debugInfo := struct {
+		InstallationDir, Origin string
+		Envelope                *application.Envelope
+		Config                  device.Config
+	}{}
+	debugInfo.InstallationDir = installationDir
+
+	if origin, err := loadOrigin(installationDir); err != nil {
+		return "", err
+	} else {
+		debugInfo.Origin = origin
+	}
+
+	currLink := filepath.Join(installationDir, "current")
+	if envelope, err := loadEnvelope(currLink); err != nil {
+		return "", err
+	} else {
+		debugInfo.Envelope = envelope
+	}
+
+	if config, err := loadConfig(installationDir); err != nil {
+		return "", err
+	} else {
+		debugInfo.Config = config
+	}
+
+	var buf bytes.Buffer
+	if err := installationDebugTemplate.Execute(&buf, debugInfo); err != nil {
+		return "", err
+	}
+	return buf.String(), nil
+
+}
+
+func (i *appService) instanceDebug(ctx ipc.ServerContext) (string, error) {
+	const instanceDebug = `Instance dir: {{.InstanceDir}}
+
+System name / start system name: {{.SystemName}} / {{.StartSystemName}}
+
+Cmd: {{printf "%+v" .Cmd}}
+
+Info: {{printf "%+v" .Info}}
+
+Principal: {{.PrincipalType}}
+Public Key: {{.Principal.PublicKey}}
+Blessing Store: {{.Principal.BlessingStore.DebugString}}
+Roots: {{.Principal.Roots.DebugString}}
+`
+	instanceDebugTemplate, err := template.New("instance-debug").Parse(instanceDebug)
+	if err != nil {
+		return "", err
+	}
+
+	instanceDir, err := i.instanceDir()
+	if err != nil {
+		return "", err
+	}
+	debugInfo := struct {
+		InstanceDir, SystemName, StartSystemName string
+		Cmd                                      *exec.Cmd
+		Info                                     *instanceInfo
+		Principal                                security.Principal
+		PrincipalType                            string
+	}{}
+	debugInfo.InstanceDir = instanceDir
+
+	debugInfo.SystemName = suidHelper.usernameForPrincipal(ctx, i.uat)
+	if startSystemName, err := readSystemNameForInstance(instanceDir); err != nil {
+		return "", err
+	} else {
+		debugInfo.StartSystemName = startSystemName
+	}
+	if cmd, err := genCmd(instanceDir, i.config.Helper, debugInfo.SystemName, veyron2.GetNamespace(ctx.Context()).Roots()); err != nil {
+		return "", err
+	} else {
+		debugInfo.Cmd = cmd
+	}
+	if info, err := loadInstanceInfo(instanceDir); err != nil {
+		return "", err
+	} else {
+		debugInfo.Info = info
+	}
+
+	if sa := i.securityAgent; sa != nil {
+		file, err := sa.keyMgrAgent.NewConnection(debugInfo.Info.SecurityAgentHandle)
+		if err != nil {
+			vlog.Errorf("NewConnection(%v) failed: %v", debugInfo.Info.SecurityAgentHandle, err)
+			return "", err
+		}
+		var cancel func()
+		if debugInfo.Principal, cancel, err = agentPrincipal(ctx.Context(), file); err != nil {
+			return "", err
+		}
+		defer cancel()
+		debugInfo.PrincipalType = "Agent-based"
+	} else {
+		credentialsDir := filepath.Join(instanceDir, "credentials")
+		var err error
+		if debugInfo.Principal, err = vsecurity.LoadPersistentPrincipal(credentialsDir, nil); err != nil {
+			return "", err
+		}
+		debugInfo.PrincipalType = fmt.Sprintf("Credentials dir-based (%v)", credentialsDir)
+	}
+	var buf bytes.Buffer
+	if err := instanceDebugTemplate.Execute(&buf, debugInfo); err != nil {
+		return "", err
+	}
+	return buf.String(), nil
+}
diff --git a/services/mgmt/device/impl/device_installer.go b/services/mgmt/device/impl/device_installer.go
index 1057bfe..ee59788 100644
--- a/services/mgmt/device/impl/device_installer.go
+++ b/services/mgmt/device/impl/device_installer.go
@@ -39,6 +39,7 @@
 	"strings"
 
 	"v.io/core/veyron2/context"
+	"v.io/core/veyron2/naming"
 	"v.io/core/veyron2/services/mgmt/application"
 	"v.io/core/veyron2/services/mgmt/device"
 
@@ -119,7 +120,7 @@
 
 // SelfInstall installs the device manager and configures it using the
 // environment and the supplied command-line flags.
-func SelfInstall(installDir, suidHelper, agent, initHelper string, singleUser, sessionMode, init bool, args, env []string, stderr, stdout io.Writer) error {
+func SelfInstall(installDir, suidHelper, agent, initHelper, origin string, singleUser, sessionMode, init bool, args, env []string, stderr, stdout io.Writer) error {
 	root := filepath.Join(installDir, dmRoot)
 	if _, err := os.Stat(root); err == nil || !os.IsNotExist(err) {
 		return fmt.Errorf("%v already exists", root)
@@ -133,6 +134,7 @@
 	configState := &config.State{
 		Name:        "dummy", // So that Validate passes.
 		Root:        root,
+		Origin:      origin,
 		CurrentLink: currLink,
 		Helper:      suidHelper,
 	}
@@ -141,7 +143,7 @@
 	}
 	var extraArgs []string
 	if name, err := os.Hostname(); err == nil {
-		extraArgs = append(extraArgs, fmt.Sprintf("--name=%q", name))
+		extraArgs = append(extraArgs, fmt.Sprintf("--name=%q", naming.Join("devices", name)))
 	}
 	if !sessionMode {
 		extraArgs = append(extraArgs, fmt.Sprintf("--restart_exit_code=%d", restartExitCode))
diff --git a/services/mgmt/device/impl/device_service.go b/services/mgmt/device/impl/device_service.go
index d53a10d..d570d3e 100644
--- a/services/mgmt/device/impl/device_service.go
+++ b/services/mgmt/device/impl/device_service.go
@@ -352,6 +352,7 @@
 		return err
 	}
 	if envelope.Title != application.DeviceManagerTitle {
+		vlog.Errorf("app title mismatch. Got %q, expected %q.", envelope.Title, application.DeviceManagerTitle)
 		return verror2.Make(ErrAppTitleMismatch, ctx)
 	}
 	if s.config.Envelope != nil && reflect.DeepEqual(envelope, s.config.Envelope) {
@@ -399,9 +400,11 @@
 		return err
 	}
 
-	if err := s.testDeviceManager(ctx, workspace, envelope); err != nil {
-		return err
-	}
+	// TODO(rthellend): testDeviceManager always fails due to https://github.com/veyron/release-issues/issues/714
+	// Uncomment when the bug is fixed.
+	//if err := s.testDeviceManager(ctx, workspace, envelope); err != nil {
+	//	return err
+	//}
 
 	if err := updateLink(filepath.Join(workspace, "deviced.sh"), s.config.CurrentLink); err != nil {
 		return err
@@ -535,3 +538,7 @@
 	}
 	return s.uat.AllBlessingSystemAssociations()
 }
+
+func (*deviceService) Debug(ipc.ServerContext) (string, error) {
+	return "Not implemented", nil
+}
diff --git a/services/mgmt/device/impl/helper_manager.go b/services/mgmt/device/impl/helper_manager.go
new file mode 100644
index 0000000..9e935d2
--- /dev/null
+++ b/services/mgmt/device/impl/helper_manager.go
@@ -0,0 +1,69 @@
+package impl
+
+import (
+	"os"
+	"os/user"
+
+	"v.io/core/veyron2/ipc"
+	"v.io/core/veyron2/verror2"
+	"v.io/core/veyron2/vlog"
+)
+
+type suidHelperState string
+
+var suidHelper suidHelperState
+
+func init() {
+	u, err := user.Current()
+	if err != nil {
+		vlog.Panicf("devicemanager has no current user: %v", err)
+	}
+	suidHelper = suidHelperState(u.Username)
+}
+
+// isSetuid is defined like this so we can override its
+// implementation for tests.
+var isSetuid = func(fileStat os.FileInfo) bool {
+	vlog.VI(2).Infof("running the original isSetuid")
+	return fileStat.Mode()&os.ModeSetuid == os.ModeSetuid
+}
+
+// unameRequiresSuidhelper determines if the the suidhelper must exist
+// and be setuid to run an application as system user un. If false, the
+// setuidhelper must be invoked with the --dryrun flag to skip making
+// system calls that will fail or provide apps with a trivial
+// priviledge escalation.
+func (dn suidHelperState) suidhelperEnabled(un, helperPath string) (bool, error) {
+	helperStat, err := os.Stat(helperPath)
+	if err != nil {
+		vlog.Errorf("Stat(%v) failed: %v. helper is required.", helperPath, err)
+		return false, verror2.Make(ErrOperationFailed, nil)
+	}
+	haveHelper := isSetuid(helperStat)
+
+	switch {
+	case haveHelper && string(dn) != un:
+		return true, nil
+	case haveHelper && string(dn) == un:
+		return false, verror2.Make(verror2.NoAccess, nil)
+	default:
+		return false, nil
+	}
+	// Keep the compiler happy.
+	return false, nil
+}
+
+// usernameForVanadiumPrincipal returns the system name that the
+// devicemanager will use to invoke apps.
+// TODO(rjkroege): This code assumes a desktop target and will need
+// to be reconsidered for embedded contexts.
+func (i suidHelperState) usernameForPrincipal(ctx ipc.ServerContext, uat BlessingSystemAssociationStore) string {
+	identityNames := ctx.RemoteBlessings().ForContext(ctx)
+	systemName, present := uat.SystemAccountForBlessings(identityNames)
+
+	if present {
+		return systemName
+	} else {
+		return string(i)
+	}
+}
diff --git a/services/mgmt/device/impl/impl_test.go b/services/mgmt/device/impl/impl_test.go
index 8b9a926..7ec36ed 100644
--- a/services/mgmt/device/impl/impl_test.go
+++ b/services/mgmt/device/impl/impl_test.go
@@ -593,6 +593,19 @@
 	// Install the app.  The config-specified flag value for testFlagName
 	// should override the value specified in the envelope above.
 	appID := installApp(t, ctx, device.Config{testFlagName: "flag-val-install"})
+	installationDebug := debug(t, ctx, appID)
+	// We spot-check a couple pieces of information we expect in the debug
+	// output.
+	// TODO(caprita): Is there a way to verify more without adding brittle
+	// logic that assumes too much about the format?  This may be one
+	// argument in favor of making the output of Debug a struct instead of
+	// free-form string.
+	if !strings.Contains(installationDebug, "Origin: ar") {
+		t.Fatalf("debug response doesn't contain expected info: %v", installationDebug)
+	}
+	if !strings.Contains(installationDebug, "Config: map[random_test_flag:flag-val-install]") {
+		t.Fatalf("debug response doesn't contain expected info: %v", installationDebug)
+	}
 
 	// Start requires the caller to grant a blessing for the app instance.
 	if _, err := startAppImpl(t, ctx, appID, ""); err == nil || !verror.Is(err, impl.ErrInvalidBlessing.ID) {
@@ -602,6 +615,11 @@
 	// Start an instance of the app.
 	instance1ID := startApp(t, ctx, appID)
 
+	instanceDebug := debug(t, ctx, appID, instance1ID)
+	if !strings.Contains(instanceDebug, "Blessing Store: Default blessings: test-principal/forapp/google naps") {
+		t.Fatalf("debug response doesn't contain expected info: %v", instanceDebug)
+	}
+
 	// Wait until the app pings us that it's ready.
 	verifyPingArgs(t, pingCh, userName(t), "flag-val-install", "env-val-envelope")
 
@@ -993,7 +1011,7 @@
 	dmDir := filepath.Join(testDir, "dm")
 	// TODO(caprita): Add test logic when initMode = true.
 	singleUser, sessionMode, initMode := true, true, false
-	if err := impl.SelfInstall(dmDir, suidHelperPath, agentPath, initHelperPath, singleUser, sessionMode, initMode, dmargs[1:], dmenv, os.Stderr, os.Stdout); err != nil {
+	if err := impl.SelfInstall(dmDir, suidHelperPath, agentPath, initHelperPath, "", singleUser, sessionMode, initMode, dmargs[1:], dmenv, os.Stderr, os.Stdout); err != nil {
 		t.Fatalf("SelfInstall failed: %v", err)
 	}
 
diff --git a/services/mgmt/device/impl/util_test.go b/services/mgmt/device/impl/util_test.go
index 0ac22f6..732ca47 100644
--- a/services/mgmt/device/impl/util_test.go
+++ b/services/mgmt/device/impl/util_test.go
@@ -241,6 +241,14 @@
 	}
 }
 
+func debug(t *testing.T, ctx *context.T, nameComponents ...string) string {
+	dbg, err := appStub(nameComponents...).Debug(ctx)
+	if err != nil {
+		t.Fatalf(testutil.FormatLogLine(2, "Debug(%v) failed: %v", nameComponents, err))
+	}
+	return dbg
+}
+
 // Code to make Association lists sortable.
 type byIdentity []device.Association
 
diff --git a/services/mgmt/suidhelper/impl/args.go b/services/mgmt/suidhelper/impl/args.go
index 67003a3..185bae8 100644
--- a/services/mgmt/suidhelper/impl/args.go
+++ b/services/mgmt/suidhelper/impl/args.go
@@ -36,7 +36,7 @@
 var (
 	flagUsername, flagWorkspace, flagLogDir, flagRun *string
 	flagMinimumUid                                   *int64
-	flagRemove                                       *bool
+	flagRemove, flagDryrun                           *bool
 )
 
 func init() {
@@ -53,6 +53,7 @@
 	flagRun = sflag.Run
 	flagMinimumUid = sflag.MinimumUid
 	flagRemove = sflag.Remove
+	flagDryrun = sflag.Dryrun
 }
 
 // ParseArguments populates the WorkParameter object from the provided args
@@ -88,6 +89,8 @@
 		return fmt.Errorf("suidhelper does not permit uids less than %d", *flagMinimumUid)
 	}
 
+	wp.dryrun = *flagDryrun
+
 	// Preserve the arguments for examination by the test harness if executed
 	// in the course of a test.
 	if os.Getenv("VEYRON_SUIDHELPER_TEST") != "" {
diff --git a/services/mgmt/suidhelper/impl/args_test.go b/services/mgmt/suidhelper/impl/args_test.go
index 9358e9f..9341fc7 100644
--- a/services/mgmt/suidhelper/impl/args_test.go
+++ b/services/mgmt/suidhelper/impl/args_test.go
@@ -85,6 +85,24 @@
 			fmt.Errorf("suidhelper does not permit uids less than 501"),
 			WorkParameters{},
 		},
+
+		{
+			[]string{"setuidhelper", "--minuid", "1", "--username", testUserName, "--workspace", "/hello",
+				"--logdir", "/logging", "--run", "/bin/veyron", "--dryrun", "--", "one", "two"},
+			[]string{"A=B"},
+			nil,
+			WorkParameters{
+				uid:       testUid,
+				gid:       testGid,
+				workspace: "/hello",
+				logDir:    "/logging",
+				argv0:     "/bin/veyron",
+				argv:      []string{"/bin/veyron", "one", "two"},
+				envv:      []string{"A=B"},
+				dryrun:    true,
+				remove:    false,
+			},
+		},
 	}
 
 	for _, c := range cases {
diff --git a/services/mgmt/suidhelper/impl/flag/flag.go b/services/mgmt/suidhelper/impl/flag/flag.go
index f8b53e1..273f56b 100644
--- a/services/mgmt/suidhelper/impl/flag/flag.go
+++ b/services/mgmt/suidhelper/impl/flag/flag.go
@@ -15,7 +15,7 @@
 var (
 	Username, Workspace, LogDir, Run *string
 	MinimumUid                       *int64
-	Remove                           *bool
+	Remove, Dryrun                   *bool
 )
 
 func init() {
@@ -29,6 +29,7 @@
 	Run = fs.String("run", "", "Path to the application to exec.")
 	MinimumUid = fs.Int64("minuid", uidThreshold, "UIDs cannot be less than this number.")
 	Remove = fs.Bool("rm", false, "Remove the file trees given as command-line arguments.")
+	Dryrun = fs.Bool("dryrun", false, "Elides root-requiring systemcalls.")
 }
 
 const uidThreshold = 501
diff --git a/services/mgmt/suidhelper/impl/system.go b/services/mgmt/suidhelper/impl/system.go
index 60a7b92..c634b59 100644
--- a/services/mgmt/suidhelper/impl/system.go
+++ b/services/mgmt/suidhelper/impl/system.go
@@ -34,22 +34,38 @@
 }
 
 func (hw *WorkParameters) Exec() error {
+	attr := new(syscall.ProcAttr)
+
+	if dir, err := os.Getwd(); err != nil {
+		log.Printf("error Getwd(): %v\n", err)
+		return fmt.Errorf("os.Getwd failed: %v", err)
+		attr.Dir = dir
+	}
+	attr.Env = hw.envv
+
+	attr.Sys = new(syscall.SysProcAttr)
+	attr.Sys.Setsid = true
 	if hw.dryrun {
 		log.Printf("[dryrun] syscall.Setgid(%d)", hw.gid)
 		log.Printf("[dryrun] syscall.Setuid(%d)", hw.uid)
 	} else {
-		// NOTE(caprita): Commenting this out since it's broken with go
-		// 1.4, to make the integration test pass.  go/vcl/8240 will fix
-		// it properly.
-
-		// if err := syscall.Setgid(hw.gid); err != nil {
-		// 	return fmt.Errorf("syscall.Setgid(%d) failed: %v", hw.gid, err)
-		// }
-		// if err := syscall.Setuid(hw.uid); err != nil {
-		// 	return fmt.Errorf("syscall.Setuid(%d) failed: %v", hw.uid, err)
-		// }
+		attr.Sys.Credential = new(syscall.Credential)
+		attr.Sys.Credential.Gid = uint32(hw.gid)
+		attr.Sys.Credential.Uid = uint32(hw.uid)
 	}
-	return syscall.Exec(hw.argv0, hw.argv, hw.envv)
+
+	_, _, err := syscall.StartProcess(hw.argv0, hw.argv, attr)
+	if err != nil {
+		if !hw.dryrun {
+			log.Printf("StartProcess failed: attr: %#v, attr.Sys: %#v, attr.Sys.Cred: %#v error: %v\n", attr, attr.Sys, attr.Sys.Credential, err)
+		} else {
+			log.Printf("StartProcess failed: %v", err)
+		}
+		return fmt.Errorf("syscall.StartProcess(%s) failed: %v", hw.argv0, err)
+	}
+	// TODO(rjkroege): Return the pid to the node manager.
+	os.Exit(0)
+	return nil // Not reached.
 }
 
 func (hw *WorkParameters) Remove() error {
diff --git a/tools/application/impl.go b/tools/application/impl.go
index 026f2c3..ef0bf9e 100644
--- a/tools/application/impl.go
+++ b/tools/application/impl.go
@@ -17,7 +17,9 @@
 	"v.io/lib/cmdline"
 )
 
-func getEnvelopeJSON(ctx *context.T, app repository.ApplicationClientMethods, profiles string) ([]byte, error) {
+func getEnvelopeJSON(app repository.ApplicationClientMethods, profiles string) ([]byte, error) {
+	ctx, cancel := context.WithTimeout(gctx, time.Minute)
+	defer cancel()
 	env, err := app.Match(ctx, strings.Split(profiles, ","))
 	if err != nil {
 		return nil, err
@@ -29,11 +31,13 @@
 	return j, nil
 }
 
-func putEnvelopeJSON(ctx *context.T, app repository.ApplicationClientMethods, profiles string, j []byte) error {
+func putEnvelopeJSON(app repository.ApplicationClientMethods, profiles string, j []byte) error {
 	var env application.Envelope
 	if err := json.Unmarshal(j, &env); err != nil {
 		return fmt.Errorf("Unmarshal(%v) failed: %v", string(j), err)
 	}
+	ctx, cancel := context.WithTimeout(gctx, time.Minute)
+	defer cancel()
 	if err := app.Put(ctx, strings.Split(profiles, ","), env); err != nil {
 		return err
 	}
@@ -66,9 +70,7 @@
 	}
 	name, profiles := args[0], args[1]
 	app := repository.ApplicationClient(name)
-	ctx, cancel := context.WithTimeout(gctx, time.Minute)
-	defer cancel()
-	j, err := getEnvelopeJSON(ctx, app, profiles)
+	j, err := getEnvelopeJSON(app, profiles)
 	if err != nil {
 		return err
 	}
@@ -81,29 +83,40 @@
 	Name:     "put",
 	Short:    "Add the given envelope to the application for the given profiles.",
 	Long:     "Add the given envelope to the application for the given profiles.",
-	ArgsName: "<application> <profiles> <envelope>",
+	ArgsName: "<application> <profiles> [<envelope>]",
 	ArgsLong: `
 <application> is the full name of the application.
 <profiles> is a comma-separated list of profiles.
-<envelope> is the file that contains a JSON-encoded envelope.`,
+<envelope> is the file that contains a JSON-encoded envelope. If this file is
+not provided, the user will be prompted to enter the data manually.`,
 }
 
 func runPut(cmd *cmdline.Command, args []string) error {
-	if expected, got := 3, len(args); expected != got {
-		return cmd.UsageErrorf("put: incorrect number of arguments, expected %d, got %d", expected, got)
+	if got := len(args); got != 2 && got != 3 {
+		return cmd.UsageErrorf("put: incorrect number of arguments, expected 2 or 3, got %d", got)
 	}
-	name, profiles, envelope := args[0], args[1], args[2]
+	name, profiles := args[0], args[1]
 	app := repository.ApplicationClient(name)
-	j, err := ioutil.ReadFile(envelope)
-	if err != nil {
-		return fmt.Errorf("ReadFile(%v): %v", envelope, err)
+	if len(args) == 3 {
+		envelope := args[2]
+		j, err := ioutil.ReadFile(envelope)
+		if err != nil {
+			return fmt.Errorf("ReadFile(%v): %v", envelope, err)
+		}
+		if err = putEnvelopeJSON(app, profiles, j); err != nil {
+			return err
+		}
+		fmt.Fprintln(cmd.Stdout(), "Application envelope added successfully.")
+		return nil
 	}
-	ctx, cancel := context.WithTimeout(gctx, time.Minute)
-	defer cancel()
-	if err = putEnvelopeJSON(ctx, app, profiles, j); err != nil {
+	env := application.Envelope{Args: []string{}, Env: []string{}, Packages: map[string]string{}}
+	j, err := json.MarshalIndent(env, "", "  ")
+	if err != nil {
+		return fmt.Errorf("MarshalIndent() failed: %v", err)
+	}
+	if err := editAndPutEnvelopeJSON(cmd, app, profiles, j); err != nil {
 		return err
 	}
-	fmt.Fprintln(cmd.Stdout(), "Application envelope added successfully.")
 	return nil
 }
 
@@ -150,6 +163,18 @@
 	}
 	name, profile := args[0], args[1]
 	app := repository.ApplicationClient(name)
+
+	envData, err := getEnvelopeJSON(app, profile)
+	if err != nil {
+		return err
+	}
+	if err := editAndPutEnvelopeJSON(cmd, app, profile, envData); err != nil {
+		return err
+	}
+	return nil
+}
+
+func editAndPutEnvelopeJSON(cmd *cmdline.Command, app repository.ApplicationClientMethods, profile string, envData []byte) error {
 	f, err := ioutil.TempFile("", "application-edit-")
 	if err != nil {
 		return fmt.Errorf("TempFile() failed: %v", err)
@@ -157,13 +182,6 @@
 	fileName := f.Name()
 	f.Close()
 	defer os.Remove(fileName)
-
-	ctx, cancel := context.WithTimeout(gctx, time.Minute)
-	defer cancel()
-	envData, err := getEnvelopeJSON(ctx, app, profile)
-	if err != nil {
-		return err
-	}
 	if err = ioutil.WriteFile(fileName, envData, os.FileMode(0644)); err != nil {
 		return err
 	}
@@ -191,7 +209,7 @@
 			fmt.Fprintln(cmd.Stdout(), "Nothing changed")
 			return nil
 		}
-		if err = putEnvelopeJSON(ctx, app, profile, newData); err != nil {
+		if err = putEnvelopeJSON(app, profile, newData); err != nil {
 			fmt.Fprintf(cmd.Stdout(), "Error: %v\n", err)
 			if ans := promptUser(cmd, "Try again? [y/N] "); strings.ToUpper(ans) == "Y" {
 				continue
diff --git a/tools/binary/impl.go b/tools/binary/impl.go
index b51f7fd..3f8ebd3 100644
--- a/tools/binary/impl.go
+++ b/tools/binary/impl.go
@@ -2,6 +2,7 @@
 
 import (
 	"fmt"
+	"os"
 
 	"v.io/core/veyron/services/mgmt/lib/binary"
 	"v.io/lib/cmdline"
@@ -71,11 +72,21 @@
 }
 
 func runUpload(cmd *cmdline.Command, args []string) error {
-	// TODO(rthellend): Add support for creating packages on the fly.
 	if expected, got := 2, len(args); expected != got {
 		return cmd.UsageErrorf("upload: incorrect number of arguments, expected %d, got %d", expected, got)
 	}
 	von, filename := args[0], args[1]
+	fi, err := os.Stat(filename)
+	if err != nil {
+		return err
+	}
+	if fi.IsDir() {
+		if err := binary.UploadFromDir(gctx, von, filename); err != nil {
+			return err
+		}
+		fmt.Fprintf(cmd.Stdout(), "Binary package uploaded from directory %s\n", filename)
+		return nil
+	}
 	if err := binary.UploadFromFile(gctx, von, filename); err != nil {
 		return err
 	}
diff --git a/tools/mgmt/device/acl_fmt.go b/tools/mgmt/device/impl/acl_fmt.go
similarity index 99%
rename from tools/mgmt/device/acl_fmt.go
rename to tools/mgmt/device/impl/acl_fmt.go
index 24091bc..05a6b05 100644
--- a/tools/mgmt/device/acl_fmt.go
+++ b/tools/mgmt/device/impl/acl_fmt.go
@@ -1,4 +1,4 @@
-package main
+package impl
 
 import (
 	"fmt"
diff --git a/tools/mgmt/device/acl_impl.go b/tools/mgmt/device/impl/acl_impl.go
similarity index 99%
rename from tools/mgmt/device/acl_impl.go
rename to tools/mgmt/device/impl/acl_impl.go
index e39f68e..dfa0cab 100644
--- a/tools/mgmt/device/acl_impl.go
+++ b/tools/mgmt/device/impl/acl_impl.go
@@ -1,4 +1,4 @@
-package main
+package impl
 
 // Commands to get/set ACLs.
 
diff --git a/tools/mgmt/device/acl_test.go b/tools/mgmt/device/impl/acl_test.go
similarity index 98%
rename from tools/mgmt/device/acl_test.go
rename to tools/mgmt/device/impl/acl_test.go
index a146e82..d195afa 100644
--- a/tools/mgmt/device/acl_test.go
+++ b/tools/mgmt/device/impl/acl_test.go
@@ -1,4 +1,4 @@
-package main
+package impl_test
 
 import (
 	"bytes"
@@ -10,6 +10,8 @@
 	"v.io/core/veyron2/security"
 	"v.io/core/veyron2/services/security/access"
 	verror "v.io/core/veyron2/verror2"
+
+	"v.io/core/veyron/tools/mgmt/device/impl"
 )
 
 const pkgPath = "v.io/core/veyron/tools/mgmt/device/main"
@@ -31,7 +33,7 @@
 	defer stopServer(t, server)
 
 	// Setup the command-line.
-	cmd := root()
+	cmd := impl.Root()
 	var stdout, stderr bytes.Buffer
 	cmd.Init(nil, &stdout, &stderr)
 	deviceName := endpoint.Name()
@@ -80,7 +82,7 @@
 	defer stopServer(t, server)
 
 	// Setup the command-line.
-	cmd := root()
+	cmd := impl.Root()
 	var stdout, stderr bytes.Buffer
 	cmd.Init(nil, &stdout, &stderr)
 	deviceName := endpoint.Name()
diff --git a/tools/mgmt/device/associate_impl.go b/tools/mgmt/device/impl/associate_impl.go
similarity index 99%
rename from tools/mgmt/device/associate_impl.go
rename to tools/mgmt/device/impl/associate_impl.go
index 1f21191..08d68f8 100644
--- a/tools/mgmt/device/associate_impl.go
+++ b/tools/mgmt/device/impl/associate_impl.go
@@ -1,4 +1,4 @@
-package main
+package impl
 
 import (
 	"fmt"
diff --git a/tools/mgmt/device/devicemanager_mock_test.go b/tools/mgmt/device/impl/devicemanager_mock_test.go
similarity index 93%
rename from tools/mgmt/device/devicemanager_mock_test.go
rename to tools/mgmt/device/impl/devicemanager_mock_test.go
index 7501383..62cf94a 100644
--- a/tools/mgmt/device/devicemanager_mock_test.go
+++ b/tools/mgmt/device/impl/devicemanager_mock_test.go
@@ -1,4 +1,4 @@
-package main
+package impl_test
 
 import (
 	"log"
@@ -68,9 +68,11 @@
 func (*mockDeviceInvoker) Describe(ipc.ServerContext) (device.Description, error) {
 	return device.Description{}, nil
 }
+
 func (*mockDeviceInvoker) IsRunnable(_ ipc.ServerContext, description binary.Description) (bool, error) {
 	return false, nil
 }
+
 func (*mockDeviceInvoker) Reset(call ipc.ServerContext, deadline uint64) error { return nil }
 
 // Mock Install
@@ -92,11 +94,13 @@
 }
 
 func (*mockDeviceInvoker) Refresh(ipc.ServerContext) error { return nil }
+
 func (*mockDeviceInvoker) Restart(ipc.ServerContext) error { return nil }
 
 func (mni *mockDeviceInvoker) Resume(_ ipc.ServerContext) error {
 	return mni.simpleCore("Resume", "Resume")
 }
+
 func (i *mockDeviceInvoker) Revert(call ipc.ServerContext) error { return nil }
 
 type StartResponse struct {
@@ -122,8 +126,11 @@
 func (mni *mockDeviceInvoker) Suspend(_ ipc.ServerContext) error {
 	return mni.simpleCore("Suspend", "Suspend")
 }
-func (*mockDeviceInvoker) Uninstall(ipc.ServerContext) error        { return nil }
-func (i *mockDeviceInvoker) Update(ipc.ServerContext) error         { return nil }
+
+func (*mockDeviceInvoker) Uninstall(ipc.ServerContext) error { return nil }
+
+func (i *mockDeviceInvoker) Update(ipc.ServerContext) error { return nil }
+
 func (*mockDeviceInvoker) UpdateTo(ipc.ServerContext, string) error { return nil }
 
 // Mock ACL getting and setting
@@ -149,6 +156,12 @@
 	return r.acl, r.etag, r.err
 }
 
+func (mni *mockDeviceInvoker) Debug(ipc.ServerContext) (string, error) {
+	ir := mni.tape.Record("Debug")
+	r := ir.(string)
+	return r, nil
+}
+
 type dispatcher struct {
 	tape *Tape
 	t    *testing.T
diff --git a/tools/mgmt/device/impl.go b/tools/mgmt/device/impl/impl.go
similarity index 65%
rename from tools/mgmt/device/impl.go
rename to tools/mgmt/device/impl/impl.go
index b62fb96..8762b8a 100644
--- a/tools/mgmt/device/impl.go
+++ b/tools/mgmt/device/impl/impl.go
@@ -1,4 +1,4 @@
-package main
+package impl
 
 import (
 	"encoding/json"
@@ -94,7 +94,7 @@
 	Long:     "Claim the device.",
 	ArgsName: "<device> <grant extension>",
 	ArgsLong: `
-<device> is the veyron object name of the device manager's app service.
+<device> is the veyron object name of the device manager's device service.
 
 <grant extension> is used to extend the default blessing of the
 current principal when blessing the app instance.`,
@@ -120,7 +120,7 @@
 	Long:     "Describe the device.",
 	ArgsName: "<device>",
 	ArgsLong: `
-<device> is the veyron object name of the device manager's app service.`,
+<device> is the veyron object name of the device manager's device service.`,
 }
 
 func runDescribe(cmd *cmdline.Command, args []string) error {
@@ -136,13 +136,71 @@
 	return nil
 }
 
-func root() *cmdline.Command {
-	return &cmdline.Command{
-		Name:  "device",
-		Short: "Tool for interacting with the veyron device manager",
-		Long: `
-The device tool facilitates interaction with the veyron device manager.
-`,
-		Children: []*cmdline.Command{cmdInstall, cmdStart, associateRoot(), cmdDescribe, cmdClaim, cmdStop, cmdSuspend, cmdResume, aclRoot()},
+var cmdUpdate = &cmdline.Command{
+	Run:      runUpdate,
+	Name:     "update",
+	Short:    "Update the device manager or application",
+	Long:     "Update the device manager or application",
+	ArgsName: "<object>",
+	ArgsLong: `
+<object> is the veyron object name of the device manager or application
+installation to update.`,
+}
+
+func runUpdate(cmd *cmdline.Command, args []string) error {
+	if expected, got := 1, len(args); expected != got {
+		return cmd.UsageErrorf("update: incorrect number of arguments, expected %d, got %d", expected, got)
 	}
+	deviceName := args[0]
+	if err := device.ApplicationClient(deviceName).Update(gctx); err != nil {
+		return err
+	}
+	fmt.Fprintln(cmd.Stdout(), "Update successful.")
+	return nil
+}
+
+var cmdRevert = &cmdline.Command{
+	Run:      runRevert,
+	Name:     "revert",
+	Short:    "Revert the device manager or application",
+	Long:     "Revert the device manager or application to its previous version",
+	ArgsName: "<object>",
+	ArgsLong: `
+<object> is the veyron object name of the device manager or application
+installation to revert.`,
+}
+
+func runRevert(cmd *cmdline.Command, args []string) error {
+	if expected, got := 1, len(args); expected != got {
+		return cmd.UsageErrorf("revert: incorrect number of arguments, expected %d, got %d", expected, got)
+	}
+	deviceName := args[0]
+	if err := device.ApplicationClient(deviceName).Revert(gctx); err != nil {
+		return err
+	}
+	fmt.Fprintln(cmd.Stdout(), "Revert successful.")
+	return nil
+}
+
+var cmdDebug = &cmdline.Command{
+	Run:      runDebug,
+	Name:     "debug",
+	Short:    "Debug the device.",
+	Long:     "Debug the device.",
+	ArgsName: "<device>",
+	ArgsLong: `
+<device> is the veyron object name of an app installation or instance.`,
+}
+
+func runDebug(cmd *cmdline.Command, args []string) error {
+	if expected, got := 1, len(args); expected != got {
+		return cmd.UsageErrorf("debug: incorrect number of arguments, expected %d, got %d", expected, got)
+	}
+	deviceName := args[0]
+	if description, err := device.DeviceClient(deviceName).Debug(gctx); err != nil {
+		return fmt.Errorf("Debug failed: %v", err)
+	} else {
+		fmt.Fprintf(cmd.Stdout(), "%v\n", description)
+	}
+	return nil
 }
diff --git a/tools/mgmt/device/impl_test.go b/tools/mgmt/device/impl/impl_test.go
similarity index 91%
rename from tools/mgmt/device/impl_test.go
rename to tools/mgmt/device/impl/impl_test.go
index 065574c..b841ee6 100644
--- a/tools/mgmt/device/impl_test.go
+++ b/tools/mgmt/device/impl/impl_test.go
@@ -1,4 +1,4 @@
-package main
+package impl_test
 
 import (
 	"bytes"
@@ -8,22 +8,12 @@
 	"strings"
 	"testing"
 
-	tsecurity "v.io/core/veyron/lib/testutil/security"
-
-	"v.io/core/veyron2"
 	"v.io/core/veyron2/naming"
 	"v.io/core/veyron2/services/mgmt/device"
 	verror "v.io/core/veyron2/verror2"
-)
 
-func initTest() (shutdown veyron2.Shutdown) {
-	var err error
-	gctx, shutdown = veyron2.Init()
-	if gctx, err = veyron2.SetPrincipal(gctx, tsecurity.NewPrincipal("test-blessing")); err != nil {
-		panic(err)
-	}
-	return shutdown
-}
+	"v.io/core/veyron/tools/mgmt/device/impl"
+)
 
 func TestListCommand(t *testing.T) {
 	shutdown := initTest()
@@ -37,7 +27,7 @@
 	defer stopServer(t, server)
 
 	// Setup the command-line.
-	cmd := root()
+	cmd := impl.Root()
 	var stdout, stderr bytes.Buffer
 	cmd.Init(nil, &stdout, &stderr)
 	deviceName := naming.JoinAddressName(endpoint.String(), "")
@@ -92,7 +82,7 @@
 	defer stopServer(t, server)
 
 	// Setup the command-line.
-	cmd := root()
+	cmd := impl.Root()
 	var stdout, stderr bytes.Buffer
 	cmd.Init(nil, &stdout, &stderr)
 	deviceName := naming.JoinAddressName(endpoint.String(), "/myapp/1")
@@ -145,7 +135,7 @@
 	defer stopServer(t, server)
 
 	// Setup the command-line.
-	cmd := root()
+	cmd := impl.Root()
 	var stdout, stderr bytes.Buffer
 	cmd.Init(nil, &stdout, &stderr)
 	deviceName := naming.JoinAddressName(endpoint.String(), "")
@@ -185,7 +175,7 @@
 	defer stopServer(t, server)
 
 	// Setup the command-line.
-	cmd := root()
+	cmd := impl.Root()
 	var stdout, stderr bytes.Buffer
 	cmd.Init(nil, &stdout, &stderr)
 	deviceName := naming.JoinAddressName(endpoint.String(), "")
@@ -278,7 +268,7 @@
 	defer stopServer(t, server)
 
 	// Setup the command-line.
-	cmd := root()
+	cmd := impl.Root()
 	var stdout, stderr bytes.Buffer
 	cmd.Init(nil, &stdout, &stderr)
 	deviceName := naming.JoinAddressName(endpoint.String(), "")
@@ -358,7 +348,7 @@
 	defer stopServer(t, server)
 
 	// Setup the command-line.
-	cmd := root()
+	cmd := impl.Root()
 	var stdout, stderr bytes.Buffer
 	cmd.Init(nil, &stdout, &stderr)
 	appName := naming.JoinAddressName(endpoint.String(), "")
@@ -428,3 +418,31 @@
 	stdout.Reset()
 	stderr.Reset()
 }
+
+func TestDebugCommand(t *testing.T) {
+	shutdown := initTest()
+	defer shutdown()
+	tape := NewTape()
+	server, endpoint, err := startServer(t, gctx, tape)
+	if err != nil {
+		return
+	}
+	defer stopServer(t, server)
+	// Setup the command-line.
+	cmd := impl.Root()
+	var stdout, stderr bytes.Buffer
+	cmd.Init(nil, &stdout, &stderr)
+	appName := naming.JoinAddressName(endpoint.String(), "")
+
+	debugMessage := "the secrets of the universe, revealed"
+	tape.SetResponses([]interface{}{debugMessage})
+	if err := cmd.Execute([]string{"debug", appName}); err != nil {
+		t.Fatalf("%v", err)
+	}
+	if expected, got := debugMessage, strings.TrimSpace(stdout.String()); got != expected {
+		t.Fatalf("Unexpected output from debug. Got %q, expected %q", got, expected)
+	}
+	if got, expected := tape.Play(), []interface{}{"Debug"}; !reflect.DeepEqual(expected, got) {
+		t.Errorf("invalid call sequence. Got %v, want %v", got, expected)
+	}
+}
diff --git a/tools/mgmt/device/instance_impl.go b/tools/mgmt/device/impl/instance_impl.go
similarity index 99%
rename from tools/mgmt/device/instance_impl.go
rename to tools/mgmt/device/impl/instance_impl.go
index b7a1fc4..3210ad4 100644
--- a/tools/mgmt/device/instance_impl.go
+++ b/tools/mgmt/device/impl/instance_impl.go
@@ -1,4 +1,4 @@
-package main
+package impl
 
 // Commands to modify instance.
 
diff --git a/tools/mgmt/device/instance_impl_test.go b/tools/mgmt/device/impl/instance_impl_test.go
similarity index 97%
rename from tools/mgmt/device/instance_impl_test.go
rename to tools/mgmt/device/impl/instance_impl_test.go
index 10f6702..08daed4 100644
--- a/tools/mgmt/device/instance_impl_test.go
+++ b/tools/mgmt/device/impl/instance_impl_test.go
@@ -1,4 +1,4 @@
-package main
+package impl_test
 
 import (
 	"bytes"
@@ -8,6 +8,8 @@
 
 	"v.io/core/veyron2/naming"
 	verror "v.io/core/veyron2/verror2"
+
+	"v.io/core/veyron/tools/mgmt/device/impl"
 )
 
 func TestStopCommand(t *testing.T) {
@@ -22,7 +24,7 @@
 	defer stopServer(t, server)
 
 	// Setup the command-line.
-	cmd := root()
+	cmd := impl.Root()
 	var stdout, stderr bytes.Buffer
 	cmd.Init(nil, &stdout, &stderr)
 	appName := naming.JoinAddressName(endpoint.String(), "")
@@ -97,7 +99,7 @@
 	defer stopServer(t, server)
 
 	// Setup the command-line.
-	cmd := root()
+	cmd := impl.Root()
 	var stdout, stderr bytes.Buffer
 	cmd.Init(nil, &stdout, &stderr)
 	appName := naming.JoinAddressName(endpoint.String(), "")
diff --git a/tools/mgmt/device/mock_test.go b/tools/mgmt/device/impl/mock_test.go
similarity index 97%
rename from tools/mgmt/device/mock_test.go
rename to tools/mgmt/device/impl/mock_test.go
index 936fc45..f08b44c 100644
--- a/tools/mgmt/device/mock_test.go
+++ b/tools/mgmt/device/impl/mock_test.go
@@ -1,4 +1,4 @@
-package main
+package impl_test
 
 import (
 	"fmt"
diff --git a/tools/mgmt/device/impl/root.go b/tools/mgmt/device/impl/root.go
new file mode 100644
index 0000000..db04609
--- /dev/null
+++ b/tools/mgmt/device/impl/root.go
@@ -0,0 +1,24 @@
+package impl
+
+import (
+	"v.io/core/veyron2/context"
+
+	"v.io/lib/cmdline"
+)
+
+var gctx *context.T
+
+func SetGlobalContext(ctx *context.T) {
+	gctx = ctx
+}
+
+func Root() *cmdline.Command {
+	return &cmdline.Command{
+		Name:  "device",
+		Short: "Tool for interacting with the veyron device manager",
+		Long: `
+The device tool facilitates interaction with the veyron device manager.
+`,
+		Children: []*cmdline.Command{cmdInstall, cmdStart, associateRoot(), cmdDescribe, cmdClaim, cmdStop, cmdSuspend, cmdResume, cmdRevert, cmdUpdate, cmdDebug, aclRoot()},
+	}
+}
diff --git a/tools/mgmt/device/impl/util_test.go b/tools/mgmt/device/impl/util_test.go
new file mode 100644
index 0000000..e108e49
--- /dev/null
+++ b/tools/mgmt/device/impl/util_test.go
@@ -0,0 +1,27 @@
+package impl_test
+
+import (
+	"v.io/core/veyron2"
+	"v.io/core/veyron2/context"
+
+	"v.io/core/veyron/lib/testutil/security"
+	_ "v.io/core/veyron/profiles"
+	"v.io/core/veyron/tools/mgmt/device/impl"
+)
+
+var gctx *context.T
+
+func initTest() veyron2.Shutdown {
+	ctx, shutdown := veyron2.Init()
+	var err error
+	if ctx, err = veyron2.SetPrincipal(ctx, security.NewPrincipal("test-blessing")); err != nil {
+		panic(err)
+	}
+	gctx = ctx
+	impl.SetGlobalContext(gctx)
+	return func() {
+		shutdown()
+		impl.SetGlobalContext(nil)
+		gctx = nil
+	}
+}
diff --git a/tools/mgmt/device/main.go b/tools/mgmt/device/main.go
index 65f7187..fc24f06 100644
--- a/tools/mgmt/device/main.go
+++ b/tools/mgmt/device/main.go
@@ -7,17 +7,15 @@
 	"os"
 
 	"v.io/core/veyron2"
-	"v.io/core/veyron2/context"
 
 	_ "v.io/core/veyron/profiles"
+	"v.io/core/veyron/tools/mgmt/device/impl"
 )
 
-var gctx *context.T
-
 func main() {
-	var shutdown veyron2.Shutdown
-	gctx, shutdown = veyron2.Init()
-	exitCode := root().Main()
+	gctx, shutdown := veyron2.Init()
+	impl.SetGlobalContext(gctx)
+	exitCode := impl.Root().Main()
 	shutdown()
 	os.Exit(exitCode)
 }
diff --git a/tools/mgmt/test.sh b/tools/mgmt/test.sh
index c42fa1d..6441eb7 100755
--- a/tools/mgmt/test.sh
+++ b/tools/mgmt/test.sh
@@ -1,8 +1,29 @@
 #!/bin/bash
 
 # Test the device manager and related services and tools.
+#
+#
+# By default, this script tests the device manager in a fashion amenable
+# to automatic testing: the --single_user is passed to the device
+# manager so that all device manager components run as the same user and
+# no user input (such as an agent pass phrase) is needed.
+#
+# When this script is invoked with the --with_suid <user> flag, it
+# installs the device manager in its more secure multi-account
+# configuration where the device manager runs under the account of the
+# invoker and test apps will be executed as <user>. This mode will
+# require root permisisons to install and may require configuring an
+# agent passphrase.
+#
+# For exanple:
+#
+#   ./test.sh --with_suid vanaguest
+#
+# to test a device manager with multi-account support enabled for app
+# account vanaguest.
+#
 
-source "$(go list -f {{.Dir}} v.io/core/shell/lib)/shell_test.sh"
+ source "$(go list -f {{.Dir}} v.io/core/shell/lib)/shell_test.sh"
 
 # Run the test under the security agent.
 shell_test::enable_agent "$@"
@@ -83,6 +104,12 @@
 }
 
 main() {
+  local -r WITH_SUID="${1:-no}"
+   if [[ "${WITH_SUID}" == "--with_suid" ]]; then
+    local -r SUID_USER="$2"
+    SUDO_USER="root"
+  fi
+
   cd "${WORKDIR}"
   build
 
@@ -90,16 +117,19 @@
   cp "${AGENTD_BIN}" "${SUIDHELPER_BIN}" "${INITHELPER_BIN}" "${DEVICEMANAGER_BIN}" "${BIN_STAGING_DIR}"
   shell_test::setup_server_test
 
-  # TODO(caprita): Expose an option to turn --single_user off, so we can run
-  # test.sh by hand and exercise the code that requires root privileges.
-
   # Install and start device manager.
   DM_INSTALL_DIR=$(shell::tmp_dir)
 
   export VANADIUM_DEVICE_DIR="${DM_INSTALL_DIR}/dm"
-  "${DEVICE_SCRIPT}" install "${BIN_STAGING_DIR}" --single_user -- --veyron.tcp.address=127.0.0.1:0
+
+  if [[ "${WITH_SUID}" == "--with_suid" ]]; then
+    "${DEVICE_SCRIPT}" install "${BIN_STAGING_DIR}" --veyron.tcp.address=127.0.0.1:0
+  else
+      "${DEVICE_SCRIPT}" install "${BIN_STAGING_DIR}" --single_user -- --veyron.tcp.address=127.0.0.1:0
+  fi
+
   "${VRUN}" "${DEVICE_SCRIPT}" start
-  local -r DM_NAME=$(hostname)
+  local -r DM_NAME=devices/$(hostname)
   DM_EP=$(wait_for_mountentry "${NAMESPACE_BIN}" 5 "${DM_NAME}")
 
   # Verify that device manager is published under the expected name (hostname).
@@ -119,6 +149,12 @@
   # Claim the device as "alice/myworkstation".
   "${DEVICE_BIN}" claim "${DM_NAME}/device" myworkstation
 
+  if [[ "${WITH_SUID}" == "--with_suid" ]]; then
+    "${DEVICE_BIN}" associate add "${DM_NAME}/device"   "${SUID_USER}"  "alice"
+     shell_test::assert_eq   "$("${DEVICE_BIN}" associate list "${DM_NAME}/device")" \
+       "alice ${SUID_USER}" "${LINENO}"
+  fi
+
   # Verify the device's default blessing is as expected.
   shell_test::assert_eq "$("${DEBUG_BIN}" stats read "${DM_NAME}/__debug/stats/security/principal/blessingstore" | head -1 | sed -e 's/^.*Default blessings: '//)" \
     "alice/myworkstation" "${LINENO}"
@@ -173,6 +209,8 @@
   # Verify that the instance shows up when globbing the device manager.
   shell_test::assert_eq "$("${NAMESPACE_BIN}" glob "${DM_NAME}/apps/BINARYD/*/*")" "${INSTANCE_NAME}" "${LINENO}"
 
+  # TODO(rjkroege): Verify that the app is actually running as ${SUID_USER}
+
   # Verify the app's default blessing.
   shell_test::assert_eq "$("${DEBUG_BIN}" stats read "${INSTANCE_NAME}/stats/security/principal/blessingstore" | head -1 | sed -e 's/^.*Default blessings: '//)" \
     "alice/myapp/BINARYD" "${LINENO}"
diff --git a/tools/servicerunner/main.go b/tools/servicerunner/main.go
index 225e19a..3e0b345 100644
--- a/tools/servicerunner/main.go
+++ b/tools/servicerunner/main.go
@@ -33,7 +33,7 @@
 	}
 	numLeft := len(varsToAdd)
 
-	s := expect.NewSession(nil, h.Stdout(), 10*time.Second)
+	s := expect.NewSession(nil, h.Stdout(), 30*time.Second)
 	for {
 		l := s.ReadLine()
 		if err := s.OriginalError(); err != nil {