blob: 8e3c46107be35b7765c6734673dc1ba8428fa1da [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package context
import (
"fmt"
"svc/svcns"
"sync"
"syscall/zx"
"syscall/zx/fdio"
"syscall/zx/fidl"
"syscall/zx/mxruntime"
"fidl/fuchsia/sys"
)
type Connector struct {
serviceRoot zx.Handle
}
type Context struct {
connector *Connector
environment *sys.EnvironmentInterface
launcher *sys.LauncherInterface
servicesMu sync.Mutex
OutgoingService *svcns.Namespace
appServices zx.Handle
serviceProvider sys.ServiceProviderService
}
// TODO: define these in syscall/zx/mxruntime
const (
HandleDirectoryRequest mxruntime.HandleType = 0x3B
HandleAppServices mxruntime.HandleType = 0x43
)
func getServiceRoot() zx.Handle {
c0, c1, err := zx.NewChannel(0)
if err != nil {
return zx.HandleInvalid
}
// TODO: Use "/svc" once that actually works.
err = fdio.ServiceConnect("/svc/.", zx.Handle(c0))
if err != nil {
return zx.HandleInvalid
}
return zx.Handle(c1)
}
func New(serviceRoot, directoryRequest, appServices zx.Handle) *Context {
c := &Context{
connector: &Connector{
serviceRoot: serviceRoot,
},
appServices: appServices,
}
c.OutgoingService = svcns.New()
if directoryRequest.IsValid() {
c.OutgoingService.ServeDirectory(zx.Channel(directoryRequest))
}
return c
}
func (c *Context) Connector() *Connector {
return c.connector
}
func (c *Context) Environment() *sys.EnvironmentInterface {
c.servicesMu.Lock()
defer c.servicesMu.Unlock()
if c.environment != nil {
return c.environment
}
r, p, err := sys.NewEnvironmentInterfaceRequest()
if err != nil {
panic(err.Error())
}
c.environment = p
c.ConnectToEnvService(r)
return c.environment
}
func (c *Context) Launcher() *sys.LauncherInterface {
c.servicesMu.Lock()
defer c.servicesMu.Unlock()
if c.launcher != nil {
return c.launcher
}
r, p, err := sys.NewLauncherInterfaceRequest()
if err != nil {
panic(err.Error())
}
c.launcher = p
c.ConnectToEnvService(r)
return c.launcher
}
func (c *Context) Serve() {
if c.appServices.IsValid() {
c.serviceProvider.Add(c.OutgoingService, zx.Channel(c.appServices), nil)
}
go fidl.Serve()
}
func (c *Context) ConnectToEnvService(r fidl.ServiceRequest) {
c.connector.ConnectToEnvService(r)
}
func (c *Connector) ConnectToEnvService(r fidl.ServiceRequest) {
c.ConnectToEnvServiceAt(r.Name(), r.ToChannel())
}
func (c *Connector) ConnectToEnvServiceAt(name string, h zx.Channel) {
err := fdio.ServiceConnectAt(c.serviceRoot, name, zx.Handle(h))
if err != nil {
panic(fmt.Sprintf("ConnectToEnvService: %v: %v", name, err))
}
}
func CreateFromStartupInfo() *Context {
directoryRequest := mxruntime.GetStartupHandle(
mxruntime.HandleInfo{Type: HandleDirectoryRequest, Arg: 0})
appServices := mxruntime.GetStartupHandle(
mxruntime.HandleInfo{Type: HandleAppServices, Arg: 0})
return New(getServiceRoot(), directoryRequest, appServices)
}