一、概述
sysmgr,负责建立一个全局系统服务的访问环境。
sysmgr的设计相当健壮。如果有任何服务死后,它们将在下一次应用程序尝试连接到该服务时自动重启。
默认情况下,sysmgr从' /system/data/sysmgr/ '读取所有配置文件。这些配置文件具有下列格式之一:
## CONFIGURATION
### Services
sysmgr服务配置文件是一个JSON文件,它由服务注册项构成。每项服务由“服务名字”和“服务应用程序URL”组成,如下。
{
"services": {
"service-name-1": "app_without_args",
"service-name-2": [
"app_with_args", "arg1", "arg2", "arg3"
]
}
}
### Apps
sysmgr apps配置文件也是 JSON 文件.它由多个app项构成, 每个app项由app的URL和/或 app args列表组成。
{
"apps": [
"app_without_args",
[ "app_with_args", "arg1", "arg2", "arg3" ]
]
}
二、服务启动及连接步骤
sysmgr启动服务步骤:
1.初始化startup context(参照上面“启动环境准备”部分)。主要是连上"/svc"总服务,打开自己的outgoing服务。
2.注册服务。从默认路径“ /system/data/sysmgr/ ”读取所有配置文件,将其中标记为"services"的服务进行注册(主要是为每个服务建立一个<servicename,callback>对应entry,加入到svc_root_目录结构中)
3.配置loader服务。将默认的fuchsia::sys::Loader加入svc_root_目录结构中。
4.为sysmgr启动的服务进程设置好运行环境(environment)。运行环境中除了1中所有“/svc”服务外,新增svc_root_目录下所有服务。
5.连接2中配置文件内,标记为“startup”的服务。这一步会启动这些服务,并创建一系列对应的废弃的channel连接这些服务(之所以说是废弃的,是因为channel的一端挂在了服务消息循环loop上,但另一端并未使用)。
6.启动2中配置文件内,标记为“apps”属性的应用。
客户端连接服务端步骤:
其实上面5就是一个比较完整的客户端连接服务端的实例,现总结如下,
1.首先客户端程序的运行环境(environment或者namespace)中,要有服务端提供服务的目录访问权限。例如,sysmgr启动的所有服务都共享其运行环境(svc_root_目录下所有服务都可以相互访问)。
2.其次,客户端程序配置cmx脚本中sandbox的services字段需要配置要访问的服务名字,如下mdns服务cmx文件:
cat garnet/bin/mdns/service/meta/mdns.cmx
{
"program": {
"binary": "bin/mdns"
},
"sandbox": {
"services": [
"fuchsia.net.SocketProvider",
"fuchsia.netstack.Netstack"
]
}
}
3.可以调用服务目录的lookup方法,对服务进行查找,如下:
fbl::RefPtr<fs::Vnode> child;
svc_root_->Lookup(&child, service_name);
4.然后在客户端创建channel,并将一端传递给服务端,如下:
zx::channel h1, h2;
zx::channel::create(0, &h1, &h2);
child->Serve(&vfs_, std::move(h1), 0);//这一步会触发服务端的回调,将client_handle绑定在服务端
5.然后通过channel的另一端与服务端通信。
序列图如下:
三、代码流程
main.cc: main()
auto command_line = fxl::CommandLineFromArgcArgv(argc, argv);//"/pkg/bin/sysmgr"
CommandLineFromIterators(argv, argv + argc); char **
CommandLineFromIteratorsFindFirstPositionalArg<InputIterator>(first, last, nullptr);
fxl::SetLogSettingsFromCommandLine(command_line)
ParseLogSettings(command_line, &settings)
async::Loop loop(&kAsyncLoopConfigMakeDefault);
Loop::Loop(const async_loop_config_t* config)
async_loop_create(config, &loop_);
async_loop_t* loop = calloc(1u, sizeof(async_loop_t));
初始化一些变量
zx_port_create(0u, &loop->port);
PortDispatcher::Create(options, &dispatcher, &rights);
PortDispatcher(options);
zx_timer_create(0u, ZX_CLOCK_MONOTONIC, &loop->timer);
zx_object_wait_async(loop->timer, loop->port, KEY_CONTROL,
ZX_TIMER_SIGNALED,
ZX_WAIT_ASYNC_REPEATING);
让port等待timer
async_set_default(&loop->async);
g_default = async;
((app.cc——》startup_context.cc))
//启动环境准备
fuchsia::sys::StartupContext::CreateFromStartupInfo()
CreateFromStartupInfoNotChecked();
directory_request = zx_take_startup_handle(PA_DIRECTORY_REQUEST);
service_root = subtle::CreateStaticServiceRootHandle()
创建通向/svc的通道
zx::channel::create(0, &h1, &h2)
fdio_service_connect("/svc/.", h1.release())
fdio_ns_connect(fdio_root_ns, svcpath, ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, h);
ns_walk_locked(&vn, &path)
fdio_open_at(vn->remote, path, flags, h);
zxrio_connect(dir, h, ZXRIO_OPEN, flags, 0755, path);
fidl_open_request(svc, cnxn, flags, mode, name, len);
request->hdr.ordinal = ZXFIDL_OPEN;
message.Write(srv, 0);
incoming_services_.Bind(std::move(service_root));
directory_ = std::move(directory);
outgoing_.Serve(std::move(directory_request));
incoming_services_.ConnectToService(environment_.NewRequest());
incoming_services_.ConnectToService(launcher_.NewRequest());
总结:连上"/svc"总服务,打开自己的服务,连上2个子服务。
//注册所有服务
sysmgr::App app;
RegisterSingleton()注册一个callback给目录服务,当有请求过来时,
要做的事情是把发过来的请求channel handle交给相应的服务。具体如下。
fuchsia::sys::Services services;
dup_launch_info.directory_request = services.NewRequest();
这里生成一个通道。一端给Services留作directory_, 另一端发给服务进程。
这样就建立了Services到服务进程的通道。
it->second.ConnectToService(std::move(client_handle), service_name);
这里会把请求通道handle通过Services的directory_发送给服务进程。
当访问一个服务路径的时候,会创建相应的服务,然后连接这个服务
it->second.ConnectToService(std::move(client_handle), service_name)
it->second的类型是component::Services
component::ConnectToService(directory_, std::move(request), service_path)
fdio_service_connect_at(directory.get(), service_path.c_str(),equest.release());
zxrio_connect(dir, h, ZXRIO_OPEN, ZX_FS_RIGHT_READABLE |
ZX_FS_RIGHT_WRITABLE, 0755, path);
zx_channel_write(svc, 0, &msg, ZXRIO_HDR_SZ + msg.datalen, msg.handle, 1)
//提供包更新loader服务
package_updating_loader_ = std::make_unique<PackageUpdatingLoader>(
std::move(update_dependency_urls), std::move(env_services),
async_get_default_dispatcher());
//建立程序运行环境
fuchsia::sys::ServiceListPtr service_list(new fuchsia::sys::ServiceList);
service_list->names = std::move(svc_names_);
service_list->host_directory = OpenAsDirectory();
startup_context_->environment()->CreateNestedEnvironment(
std::move(env_request), env_controller_.NewRequest(), kDefaultLabel,
std::move(service_list), {});
//连接“startup_services”属性的服务(属于开机自启动服务,例如mdns、netconnector、amber等)
ConnectToService(startup_service, std::move(h1));
startup_service是通过解析config文件得来(config.TakeStartupServices())
svc_root_->Lookup(&child, service_name);
child->Serve(&vfs_, std::move(channel), 0);
通过channel连接服务
//启动app(有“apps”属性,属于开机自启动)
LaunchApplication(std::move(*launch_info));
launch_info来自解析config文件(config.TakeApps())
env_launcher_->CreateComponent(std::move(launch_info), nullptr);
class Config分析
Config::ParseFromDirectory函数:
json_parser_.ParseFromDirectory(dir, cb);
调用json parser的同名函数,将目录dir下json config文件合并到一起
ParseDocument(std::move(document));
会调用上面构造的cb函数,这个函数会吧json config文件中的service、app、startup_services、update_dependencies信息分别获取并存在成员变量中
先看一下sysmgr是如何与appmgr里的fuchsia::sys::Launcher建立通道的(FIDL调用部分参照原晨旭分析)。
sysmgr:
env_launcher_.NewRequest()
InterfaceRequest<Interface> NewRequest() 这个方法创建一个channel, 自己留下一头,
把另一头封在InterfaceRequest<Interface>()里返回出来。
留下的那头会自动bind上,但是没什么用,因为是默认的处理。
env_->GetLauncher(env_launcher_.NewRequest());
->会返回&impl_->proxy
impl_是InterfacePtr<T>::Impl,里面的proxy是Interface::Proxy_,另外还有一个ProxyController.
Environment_Proxy::GetLauncher(::fidl::InterfaceRequest<Launcher> launcher)
controller_->Send(&fuchsia_sys_EnvironmentGetLauncherRequestTable, _encoder.GetMessage(), nullptr);
message.Write(reader_.channel().get(), 0);
appmgr:
Namespace::GetLauncher(fidl::InterfaceRequest<Launcher> launcher)
launcher_bindings_.AddBinding(this, std::move(launcher));
std::make_unique<Binding>(std::forward<ImplPtr>(impl),std::move(request))
Binding与InterfacePtr<>::Impl相对应,里面有Interface::Stub_和StubController
Bind(request.TakeChannel(), async);
controller_.reader().Bind(std::move(channel), async);
wait_.object = channel_.get();
async_begin_wait(async_, &wait_);
async->ops->v1.begin_wait(async, wait);
zx_object_wait_async(wait->object, loop->port, (uintptr_t)wait, wait->trigger, ZX_WAIT_ASYNC_ONCE);
等下次通信的时候,会调用wait对象里的handler.
sysmgr启动app通过fuchsia::sys::Launcher::CreateComponent().
调用的是appmgr里的Namespace::CreateComponent()
sysmgr:
env_launcher_->CreateComponent(std::move(launch_info), nullptr);
appmgr:
realm_->CreateComponent(std::move(launch_info), std::move(controller));