v.io/x/ref: add namespace factory option to rt.Init()

This option will be used by the android runtime to override
default namespace creation.  We need this functionality in order
to implement remote GCM wakeups, which are performed by the
special mounttable we run.

Change-Id: I6b20329a550a07c84c41c2a9412c64f860803473
diff --git a/runtime/factories/android/android.go b/runtime/factories/android/android.go
index 5704786..49c376a 100644
--- a/runtime/factories/android/android.go
+++ b/runtime/factories/android/android.go
@@ -19,6 +19,7 @@
 	"v.io/v23"
 	"v.io/v23/context"
 	"v.io/v23/flow"
+	"v.io/v23/namespace"
 	"v.io/v23/rpc"
 
 	"v.io/x/ref/internal/logger"
@@ -30,6 +31,7 @@
 	"v.io/x/ref/runtime/internal/lib/appcycle"
 	"v.io/x/ref/runtime/internal/lib/roaming"
 	"v.io/x/ref/runtime/internal/lib/xwebsocket"
+	inamespace "v.io/x/ref/runtime/internal/naming/namespace"
 	"v.io/x/ref/runtime/internal/rt"
 	_ "v.io/x/ref/runtime/protocols/tcp"
 	_ "v.io/x/ref/runtime/protocols/ws"
@@ -37,18 +39,29 @@
 	"v.io/x/ref/services/debug/debuglib"
 )
 
+var (
+	commonFlags      *flags.Flags
+	namespaceFactory inamespace.Factory
+)
+
 const (
 	connIdleExpiry = 15 * time.Second
 )
 
-var commonFlags *flags.Flags
-
 func init() {
 	v23.RegisterRuntimeFactory(Init)
 	flow.RegisterUnknownProtocol("wsh", xwebsocket.WSH{})
 	commonFlags = flags.CreateAndRegister(flag.CommandLine, flags.Runtime, flags.Listen)
 }
 
+// Sets the namespace factory to be used for creating all namespaces.
+//
+// If never invoked, a default namespace factory will be used.  If invoked,
+// must be before Init() function below, i.e., before v23.Init().
+func SetNamespaceFactory(factory func(*context.T, namespace.T, ...string) (namespace.T, error)) {
+	namespaceFactory = inamespace.Factory(factory)
+}
+
 func Init(ctx *context.T) (v23.Runtime, *context.T, v23.Shutdown, error) {
 	if err := internal.ParseFlagsAndConfigureGlobalLogger(commonFlags); err != nil {
 		return nil, nil, nil, err
@@ -76,7 +89,7 @@
 
 	publisher := pubsub.NewPublisher()
 
-	runtime, ctx, shutdown, err := rt.Init(ctx, ac, discoveryFactory, nil, &listenSpec, publisher, commonFlags.RuntimeFlags(), reservedDispatcher, connIdleExpiry)
+	runtime, ctx, shutdown, err := rt.Init(ctx, ac, discoveryFactory, namespaceFactory, nil, &listenSpec, publisher, commonFlags.RuntimeFlags(), reservedDispatcher, connIdleExpiry)
 	if err != nil {
 		ishutdown()
 		return nil, nil, nil, err
diff --git a/runtime/factories/chrome/chrome.go b/runtime/factories/chrome/chrome.go
index 9bde6ab..ed49651 100644
--- a/runtime/factories/chrome/chrome.go
+++ b/runtime/factories/chrome/chrome.go
@@ -37,7 +37,7 @@
 
 	protocols := []string{"wsh", "ws"}
 	listenSpec := rpc.ListenSpec{Addrs: rpc.ListenAddrs{{Protocol: "ws", Address: ""}}}
-	runtime, ctx, shutdown, err := grt.Init(ctx, nil, nil, protocols, &listenSpec, nil, commonFlags.RuntimeFlags(), nil, 0)
+	runtime, ctx, shutdown, err := grt.Init(ctx, nil, nil, nil, protocols, &listenSpec, nil, commonFlags.RuntimeFlags(), nil, 0)
 	if err != nil {
 		return nil, nil, nil, err
 	}
diff --git a/runtime/factories/gce/gce.go b/runtime/factories/gce/gce.go
index a28801c..b230fc6 100644
--- a/runtime/factories/gce/gce.go
+++ b/runtime/factories/gce/gce.go
@@ -64,7 +64,7 @@
 		})
 	}
 
-	runtime, ctx, shutdown, err := grt.Init(ctx, ac, nil, nil, &listenSpec, nil, commonFlags.RuntimeFlags(), nil, 0)
+	runtime, ctx, shutdown, err := grt.Init(ctx, ac, nil, nil, nil, &listenSpec, nil, commonFlags.RuntimeFlags(), nil, 0)
 	if err != nil {
 		ac.Shutdown()
 		return nil, nil, nil, err
diff --git a/runtime/factories/generic/generic.go b/runtime/factories/generic/generic.go
index de7c2a6..ac3a0d6 100644
--- a/runtime/factories/generic/generic.go
+++ b/runtime/factories/generic/generic.go
@@ -58,7 +58,7 @@
 		discoveryFactory.Shutdown()
 	}
 
-	runtime, ctx, shutdown, err := grt.Init(ctx, ac, discoveryFactory, nil, &listenSpec, nil, commonFlags.RuntimeFlags(), nil, 0)
+	runtime, ctx, shutdown, err := grt.Init(ctx, ac, discoveryFactory, nil, nil, &listenSpec, nil, commonFlags.RuntimeFlags(), nil, 0)
 	if err != nil {
 		ishutdown()
 		return nil, nil, nil, err
diff --git a/runtime/factories/roaming/roaming.go b/runtime/factories/roaming/roaming.go
index 926e486..e8e6ea3 100644
--- a/runtime/factories/roaming/roaming.go
+++ b/runtime/factories/roaming/roaming.go
@@ -72,7 +72,7 @@
 
 	publisher := pubsub.NewPublisher()
 
-	runtime, ctx, shutdown, err := rt.Init(ctx, ac, discoveryFactory, nil, &listenSpec, publisher, commonFlags.RuntimeFlags(), reservedDispatcher, 0)
+	runtime, ctx, shutdown, err := rt.Init(ctx, ac, discoveryFactory, nil, nil, &listenSpec, publisher, commonFlags.RuntimeFlags(), reservedDispatcher, 0)
 	if err != nil {
 		ishutdown()
 		return nil, nil, nil, err
diff --git a/runtime/internal/naming/namespace/namespace.go b/runtime/internal/naming/namespace/namespace.go
index d02494f..f657b47 100644
--- a/runtime/internal/naming/namespace/namespace.go
+++ b/runtime/internal/naming/namespace/namespace.go
@@ -9,6 +9,7 @@
 	"time"
 
 	"v.io/v23/context"
+	vnamespace "v.io/v23/namespace"
 	"v.io/v23/naming"
 	"v.io/v23/options"
 	"v.io/v23/rpc"
@@ -29,7 +30,7 @@
 	errNotRootedName = verror.Register(pkgPath+".errNotRootedName", verror.NoRetry, "{1:}{2:} At least one root is not a rooted name{:_}")
 )
 
-// namespace is an implementation of naming.Namespace.
+// namespace is an implementation of namespace.T.
 type namespace struct {
 	sync.RWMutex
 
@@ -44,6 +45,10 @@
 	resolutionCache cache
 }
 
+// Factory creates a new namespace given a default namespace and a set
+// of roots.
+type Factory func(*context.T, vnamespace.T, ...string) (vnamespace.T, error)
+
 func rooted(names []string) bool {
 	for _, n := range names {
 		if a, _ := naming.SplitAddressName(n); len(a) == 0 {
@@ -71,7 +76,7 @@
 	}, nil
 }
 
-// SetRoots implements naming.Namespace.SetRoots
+// SetRoots implements namespace.T.SetRoots
 func (ns *namespace) SetRoots(roots ...string) error {
 	defer apilog.LogCallf(nil, "roots...=%v", roots)(nil, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
 	// Allow roots to be cleared with a call of SetRoots()
@@ -95,7 +100,7 @@
 	}
 }
 
-// Roots implements naming.Namespace.Roots
+// Roots implements namespace.T.Roots
 func (ns *namespace) Roots() []string {
 	//nologcall
 	ns.RLock()
@@ -182,7 +187,7 @@
 	return ctx
 }
 
-// CacheCtl implements naming.Namespace.CacheCtl
+// CacheCtl implements namespace.T.CacheCtl
 func (ns *namespace) CacheCtl(ctls ...naming.CacheCtl) []naming.CacheCtl {
 	defer apilog.LogCallf(nil, "ctls...=%v", ctls)(nil, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
 	for _, c := range ctls {
diff --git a/runtime/internal/rpc/resolve_test.go b/runtime/internal/rpc/resolve_test.go
index 326cfec..e5b1e0a 100644
--- a/runtime/internal/rpc/resolve_test.go
+++ b/runtime/internal/rpc/resolve_test.go
@@ -44,6 +44,7 @@
 		ac,
 		nil,
 		nil,
+		nil,
 		&listenSpec,
 		nil,
 		commonFlags.RuntimeFlags(),
diff --git a/runtime/internal/rt/runtime.go b/runtime/internal/rt/runtime.go
index 0574433..649e15b 100644
--- a/runtime/internal/rt/runtime.go
+++ b/runtime/internal/rt/runtime.go
@@ -66,6 +66,7 @@
 type initData struct {
 	appCycle          v23.AppCycle
 	discoveryFactory  idiscovery.Factory
+	namespaceFactory  inamespace.Factory
 	protocols         []string
 	settingsPublisher *pubsub.Publisher
 	connIdleExpiry    time.Duration
@@ -85,6 +86,7 @@
 	ctx *context.T,
 	appCycle v23.AppCycle,
 	discoveryFactory idiscovery.Factory,
+	namespaceFactory inamespace.Factory,
 	protocols []string,
 	listenSpec *rpc.ListenSpec,
 	settingsPublisher *pubsub.Publisher,
@@ -96,6 +98,7 @@
 	ctx = context.WithValue(ctx, initKey, &initData{
 		appCycle:          appCycle,
 		discoveryFactory:  discoveryFactory,
+		namespaceFactory:  namespaceFactory,
 		protocols:         protocols,
 		settingsPublisher: settingsPublisher,
 		connIdleExpiry:    connIdleExpiry,
@@ -322,18 +325,21 @@
 }
 
 func (r *Runtime) setNewNamespace(ctx *context.T, roots ...string) (*context.T, namespace.T, error) {
-	ns, err := inamespace.New(roots...)
-	if err != nil {
+	id, _ := ctx.Value(initKey).(*initData)
+	var ns namespace.T
+	var err error
+	if ns, err = inamespace.New(roots...); err != nil {
 		return nil, nil, err
 	}
-
+	if id.namespaceFactory != nil {
+		if ns, err = id.namespaceFactory(ctx, ns, roots...); err != nil {
+			return nil, nil, err
+		}
+	}
 	if oldNS := r.GetNamespace(ctx); oldNS != nil {
 		ns.CacheCtl(oldNS.CacheCtl()...)
 	}
-
-	if err == nil {
-		ctx = context.WithValue(ctx, namespaceKey, ns)
-	}
+	ctx = context.WithValue(ctx, namespaceKey, ns)
 	return ctx, ns, err
 }