sysmgr分析

一、概述

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));

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值