一.概述

appmgr启动:
devmgr——>fuchsia_starter
1.等待fshost准备好/system目录
2.调用coordinator方法,扫描system目录下的driver
3.将devmgr中与appmgr通信的channel的一端——appmgr_server传给appmgr(后续可以利用appmgr_client访问appmgr的服务)
4.调用devmgr_launch启动appmgr服务进程(传入除hub目录外的所有目录的Namespace)

appmgr里主要做了三个事情:

1.构造根realm对象

2.通过devmgr传过来的PA_DIRECTORY_REQUEST句柄,对外提供hub目录服务,以及子环境(sysmgr)的svc目录服务

3.启动sysmgr,并对sysmgr提供crash重启服务

async::PostTask(async_dispatcher_t* dispatcher, fbl::Closure handler)

说明:Posts a task to invoke |handler| with a deadline of now。主要作用是延时启动一个进程来执行handler回调,此函数延时时间为0,PostDelayedTask函数提供延时参数,原型如下:

zx_status_t PostDelayedTask(async_dispatcher_t* dispatcher, fbl::Closure handler, zx::duration delay);

二、类图分析

主要类分析::

Appmgr类:
1.构造根realm对象
2.通过devmgr传过来的PA_DIRECTORY_REQUEST句柄,对外提供hub目录服务,以及子环境(sysmgr)的svc目录服务
3.启动sysmgr,并对sysmgr提供crash重启服务

Realm类:
1.构造函数
1.1创建appmgr根job对象——“app”
1.2对于app的根运行环境(appmgr的root realm)创建svc的client和server句柄--看后面怎么使用!
1.3构造缺省Namespace对象(见Namespace类分析)
1.4设置hub对象name(添加“/hub/name”节点,值为“app”);
                         job-id(添加“/hub/job-id”节点,值为进程号);
                         job_provider(添加“/hub/job”节点,值为lamda回调);
                         services(添加“/hub/svc”节点,值为1.3缺省Namespace对象的service服务);
1.5为缺省Namespace对象添加loader服务(这也会体现在“/hub/svc”节点)
1.6缺省Namespace对象绑定service_provider服务
1.7成员变量loader_保存与fuchsia::sys::Loader服务的联系接口

2.nested运行环境的创建(CreateNestedEnvironment)
2.1检查子环境label的有效性、是否与现存的child重复
2.2检查additional_services及其host_directory
2.3构建nested_data_path——"/data/r/‘label’"(sysmgr举例‘label’为sys)
2.4构建RealmArgs对象,进而构建子Realm对象(sysmgr,label为sys)
2.5构造EnvironmentControllerImpl对象
2.6子realm对象绑定environment(会调用namespace的binding,见Namespace分析)
2.7将子realm对象的hubinfo信息添加到根realm(label为sys,TODO:sys的上一级目录r在哪里创建?:RealmHub初始化时会创建“r”和“c”目录)
2.8将子realm对象的缺省Namespace对象的services_服务与根realm的svc_channel_server_进行绑定
2.9将子realm对象与其EnvironmentControllerImpl对象组成的map放入根realm的children_里管理起来
2.10虚拟终端创建(TODO)

3.子组件创建(CreateComponent)
3.1检查子组件url不能为空
3.2规范化url(如果url中不存在“:”则加上"file://"前缀,否则直接返回url)
3.3获取url的scheme(“:”前面的部分,例如“file”、“fuchsia-pkg”)
3.4如果launcher_type为package(3.3中“file、fuchsia-pkg”都为package类型),则调用1.7中loader的LoadUrl函数创建子组件
//PackageLoader::LoadUrl
3.5解析url信息,以sysmgr举例:fuchsia-pkg://fuchsia.com/sysmgr#meta/sysmgr.cmx,匹配正则表达式,获取包目录(“/pkgfs/packages/sysmgr/0”)、获取资源文件路径(“meta/sysmgr.cmx”)
3.6open组件包目录,并clone访问目录handler到directory
3.7LoadResource(获取cmx文件vmo)
3.8利用前面获取的resolved_url、directory及vmo对象构造package对象,并传给LoadUrl的lamda回调
//lamda回调调用CreateComponentFromPackage函数
3.9调用CmxMetadata::ParseFromFileAt解析cmx文件,获取sandbox、runtime和program等信息
3.10保存elf的path、args、vmo信息
3.11创建包目录相关loader_service
3.12构建NamespaceBuilder对象,保存包目录句柄、sandbox相关信息(包括dev、system、pkgfs、boot、shell等)
3.13构建缺省Namespace对象,保存sandbox中service入白名单、保存组件的url、并将Namespace的service添加到3.12的builder中保存
3.14加入custom namespace(TODO)
3.15将3.9——3.14构造的参数传给CreateElfBinaryComponentFromPackage处理
//CreateElfBinaryComponentFromPackage
3.16创建子job
3.17调用CreateProcess创建子进程
3.18组件管理相关后处理(构造ComponentControllerImpl对象、更新hub目录<增加组件子目录树>、将ComponentControllerImpl对象放入applications_中管理起来)
//CreateProcess
3.19获取job、label、argv信息
3.20在fdio_spawn_action_t向量中保存job句柄
                                                             loader_service句柄
                                                             directory_request句柄
                                                             STDIN_FILENO句柄
                                                             STDOUT_FILENO句柄
                                                             STDERR_FILENO句柄
3.21在fdio_spawn_action_t向量中设置name、添加Namespace
3.22调用fdio_spawn_vmo传入前面构建的action对象创建进程(参见svchost分析)

序列图如下:

4.子组件的销毁(ExtractComponent)
从组件管理对象applications_的map中移除对应component,更新hub信息。

Namespace类:

继承了3个服务类(fuchsia::sys::Environment、fuchsia::sys::Launcher、fuchsia::process::Resolver),所以它可以具有3个服务类的属性,对外提供服务。从继承关系来看,Namespace类相当于一堆服务的集合。
1.构造函数
1.1利用提供的服务白名单(service_whitelist)初始化services_对象
1.2利用提供的realm对象指针初始化job_provider_对象
1.3初始化realm_对象
1.4services_加入fuchsia::sys::Environment、Launcher、fuchsia::process::Launcher、fuchsia::process::Resolver服务
1.5services_加入additional_services
1.5加入parent的所有服务

ComponentControllerImpl类:

继承自ComponentControllerBase类,主要提供AddSubComponentHub、RemoveSubComponentHub、Kill方法。
1.构造函数:
1.1调用ComponentControllerBase构造函数
  //ComponentControllerBase()
  1.2绑定request,方便组件管理
  1.3将launchinfo中的directory_request加入消息循环,监听上
  1.4添加out目录,根据情况(文件是否在meta/legacy_flat_exported_dir目录)增加不同文件节点“ctrl、debug、public”或者“object”
  1.5设置ComponentHub的“name”、“url”、“args”
  //
1.6设置ComponentHub的“job-id”、“process-id”、“system_objects”
1.7从Namespace获取services作为incoming_services,添加到in/svc目录下

EnvironmentControllerImpl类:
realm的管理结构。包含一个realm的指针和一个EnvironmentController服务的binding对象。提供Kill和Detach方法用于将realm从父realm中移除操作。

三、代码调用链分析

async::Loop loop(&kAsyncLoopConfigAttachToThread)

async_loop_create(config, &loop_)

request = zx_take_startup_handle(PA_DIRECTORY_REQUEST)
    获取访问appmgr目录的句柄

component::AppmgrArgs args{
    .pa_directory_request = std::move(request),
    ……};构造参数

component::Appmgr appmgr(loop.dispatcher(), std::move(args));
    构造函数初始化appmgr对象
    // 1. Create root realm.——“/data/app”
    RealmArgs realm_args =
        RealmArgs::Make(nullptr, kRootLabel, "/data", args.environment_services,
                                    args.run_virtual_console,
                                    /*inherit_parent_services=*/false,
                                   /*kill_on_oom=*/false);//kRootLabel值为“app”
    root_realm_ = std::make_unique<Realm>(std::move(realm_args));
    // 2. Publish outgoing directories.
    auto svc = fbl::AdoptRef(new fs::Service([this](zx::channel channel) {
             return root_realm_->BindSvc(std::move(channel));
     }));//打开这个node可以绑定channel到服务
    publish_dir_->AddEntry("hub", root_realm_->hub_dir());//公开hub目录
    publish_dir_->AddEntry("svc", svc);//公开svc目录
          让"svc、hub"对应到一个fs::Service上。Service是Vnode的一种。
           Connector = fbl::Function<zx_status_t(zx::channel channel)>;
    publish_vfs_.ServeDirectory(publish_dir_,
                                                   zx::channel(args.pa_directory_request));
                                                    //在指定channel上服务vnode 
              vfs.ServeDirectory(directory, std::move(h2)
                  请求从h2进来
                  // Tell the calling process that we've mounted the directory.
                    r = channel.signal_peer(0, ZX_USER_SIGNAL_0)
                    vn->Serve(this, fbl::move(channel), ZX_FS_RIGHT_ADMIN);//admin权限很高了(读、写、mount)
                           vfs->ServeConnection(fbl::make_unique<Connection>(vfs, fbl::WrapRefPtr(this), fbl::move(channel), flags));
                                      connection->Serve()
                                               wait_.set_object(channel_.get());//设置等待消息的channel
                                                           wait_.object = object;
                                                wait_.Begin(vfs_->dispatcher());
                                                        async_begin_wait(dispatcher, &wait_)
                                                                  dispatcher->ops->v1.begin_wait(dispatcher, wait)
                                                                            async_loop_begin_wait(,)//zircon/system/ulib/async-loop/loop.c:53
                                                                                     zx_object_wait_async(
                                                                                              wait->object, loop->port, (uintptr_t)wait, wait->trigger,                                                                                                                             ZX_WAIT_ASYNC_ONCE);
                                                                                     把前面那个h2挂到async loop的port上
                    ?h1交给Realm, 让Realm能够向appmgr这个服务发送请求
                    接下来仔细看看Realm的构造

component::Realm root_realm(nullptr, std::move(h1), kRootLabel)
         parent_是空
         构造一个缺省的default_namespace_
         Namespace(nullptr, this, std::move(args.additional_services), nullptr)
                         services_.set_backend(std::move(services_backend)); ServiceProviderBridge

services_.AddService<Environment>(
                                   [this](fidl::InterfaceRequest<Environment> request) {
                                                    environment_bindings_.AddBinding(this, std::move(request));
                                  });

AddServiceForName()
                                      name_to_service_connector_[service_name] = std::move(connector);

构造RealmHub
           vfs获取缺省的async

zx::channel::create(0, &svc_channel_server_, &svc_channel_client_)
           看看后面怎么用这个通道

hub_.AddServices(default_namespace_->services());
           default_namespace_->services().set_backing_dir(std::move(host_directory))
                       把通向"component.Loader"目录服务的通道赋值给ServiceProviderDirImpl的backing_dir_

ServiceProviderPtr service_provider;
                     ServiceProviderPtr是InterfacePtr<ServiceProvider>
              我们先看这个函数调用,
              service_provider.NewRequest()//garnet/public/lib/svc/cpp/services.cc:31
                            zx::channel::create(0, &h1, &h2)
                                      创建一个通道,一头给Bind(),另一头返回
                            Bind(std::move(h1), async) 
                                     impl_->controller.reader().Bind(std::move(channel), async)
                                               impl里有ServiceProvider::Proxy_ 和 fidl::internal::ProxyController
                                               ProxyController里的MessageReader reader_监听h1
                                               wait_.object = channel_.get()
                                               async_begin_wait(async_, &wait_)

controller收到消息会调用proxy_->Dispatch_()
                            h1这头的处理目前看好像是fidl生成的缺省代码
                            service_provider应该是作为客户端,所以还不需要处理返回的消息

return InterfaceRequest<ServiceProvider>(std::move(h2));
                                       返回h2

ServiceProviderBridge::AddBinding(h2)
                            bindings_.AddBinding(this, std::move(request))
                                      this是ServiceProviderBridge自己 ImplPtr=ServiceProviderBridge*
                                      Binding(impl, request)
                                                Binding(std::forward<ImplPtr>(impl)
                                                        impl_(std::forward<ImplPtr>(impl)), stub_(&*this->impl())
                                                                   stub_是ServiceProvider::Stub_,这个类的Dispatch_()会调用impl的ConnectToService(),
                                                                    也就是ServiceProviderBridge::ConnectToService()
                                                  controller_.reader().Bind(std::move(channel), async);
                                                                    这里设置处理来自service_provider的请求
                                                                     把channel挂到事件循环上

bindings_.push_back()
                                               binding的类型是这个::fidl::Binding<ServiceProvider, InterfaceRequest<ServiceProvider>>

建立了一个通道,一头让ServiceProvider::Proxy_处理,另一头给了ServiceProviderBridge添加binding,监听上

service_provider.get()
                                返回impl里的ServiceProvider::Proxy_ 它继承了ServiceProvider

下面这个ConnectToService的定义在connect.h里
                     loader_ = ConnectToService<Loader>(ServiceProvider::Proxy_) 模板类型是Loader,                                                                           interface_name="component.Loader"
                             这里service_provider是ServiceProvider::Proxy_

InterfacePtr<Loader> interface_ptr
                             先看interface_ptr.NewRequest()
                                         创建通道,一头h1是Loader::Proxy_缺省处理,另一头h2返回

service_provider->ConnectToService("component.Loader",h2)
                                       这个函数是fidl生成的
                                       controller_->Send
                                       把h2发送给了ServiceProviderDirImpl,因为之前通道的另一头给了                                                                                                       ServiceProviderDirImpl::AddBinding(h2)
                                       ServiceProviderDirImpl::ConnectToService()会被调用,把h2发送给RootLoader::AddBinding监听起来
                                        fdio_service_connect_at()
                                                RootLoader::AddBinding

返回InterfacePtr<Loader>
                   上面这段代码的含义就是通过service_provider建立和Loader这个服务的联系
                    service_provider是个客户端,它被AddBinding到ServiceProviderBridge里。
                    ServiceProviderDirImpl本身是个服务,它的唯一的服务内容就是去ConnectToService()

PublishRootDir(&root_realm, &publish_vfs);
      request = zx_get_startup_handle(PA_DIRECTORY_REQUEST)
      dir(fbl::AdoptRef(new fs::PseudoDir()
      svc = fbl::AdoptRef(new fs::Service([root](zx::channel channel) {
           return root->BindSvc(std::move(channel));
       }));
                  碰到Serve请求会调用这个函数。
                  fdio_service_clone_to(root_realm->svc_channel_client_.get(),channel.release());
                                     zxrio_connect(svc, srv, ZXRIO_CLONE, ZX_FS_RIGHT_READABLE |ZX_FS_RIGHT_WRITABLE, 0755,                       "");
                              把channel发送给svc
                   这里有点奇怪,svc_channel_client_的另一头要等到sysmgr调用CreateNestedEnvironment才会被监听

dir->AddEntry("hub", root->hub_dir());
               hub_.dir()
                   dir_
        dir->AddEntry("svc", svc);

publish_vfs_.ServeDirectory(publish_dir_, zx::channel(args.pa_directory_request));
         把从devmgr发来的通道挂到目录服务上
          OpenVnode(flags, &vn)
                   (*vnode)->Open(flags, &redirect)
                            PseudoDir::Open()啥也不干
          vn->Serve(this, fbl::move(channel), ZX_FS_RIGHT_ADMIN)
                 vfs->ServeConnection(fbl::make_unique<Connection>(vfs, fbl::WrapRefPtr(this), fbl::move(channel), flags));
                       connection->Serve();
                              wait_.set_object(channel_.get());
                              wait_.Begin(vfs_->async());

run_sysmgr()
         fuchsia::sys::LaunchInfo launch_info;
                   LaunchInfo是fidl生成的, launcher.fidl
          sysmgr.NewRequest() InterfacePtr<ComponentController>
                  Bind(std::move(h1), async)
                       impl_->controller.reader().Bind(std::move(channel), async);
                              wait_.object = channel_.get();
                              async_begin_wait(async_, &wait_)
                 ComponentController_Proxy缺省处理
                 返回另一头h2

root_realm.CreateComponent(std::move(launch_info),h2);
        (######
        $ cat /system/data/appmgr/scheme_map/default.config
        {
              "launchers": {
              "package": [ "file", "fuchsia-pkg" ],
                     "fuchsia-pkg://fuchsia.com/web_runner#meta/web_runner.cmx": [ "http", "https" ],
                     "fuchsia-pkg://fuchsia.com/cast_runner#meta/cast_runner.cmx": [ "cast", "casts" ]
               }
        }
        )
        scheme = "package"
         cb = lambda
         loader_->LoadUrl(url, cb)
                       CreateComponentFromPackage()
                       获取cmx路径
                                 cmx.ParseFromFileAt(fd.get(), cmx_path, &json_parser)
                                 runtime.IsNull()//yes
                                 VmoFromFilenameAt//通过文件名获取VMO
                                  DynamicLibraryLoader::Start(std::move(fd), &loader_service)
                                 builder.AddSandbox
                                           分别向dev、system、pkgfs目录下pushdir(如果有配置)
                                           向data目录pushdir
                                            根据沙箱feature属性添加目录
                                           向boot目录pushdir
                                 builder.AddServices(ns->OpenServicesAsDirectory())
                                          OpenAsDirectory
                                                      vfs->ServeDirectory(std::move(node), std::move(h1))
                                  builder.AddFlatNamespace
                                  CreateElfBinaryComponentFromPackage//用默认的runner运行elf
                                              zx::job::create(job_, 0u, &child_job)//创建一个子job
                                              CreateProcess//创建进程
                                               创建一个组件管理对象ComponentControllerImpl,并添加到hub

RootLoader::LoadComponent(fidl::StringPtr url,
                                                 LoadComponentCallback callback)
            CreateComponentWithProcess(
                                               std::move(package), std::move(launch_info),
                                               std::move(controller), std::move(ns));

builder.AddServices(std::move(svc));
                                  PushDirectoryFromChannel("/svc", std::move(services));
                                           这里设置了sysmgr的"/svc"指向appmgr的服务
                      flat namespace没有
                      channels = Util::BindDirectory(&launch_info);
                             launch_info->directory_request = std::move(exported_dir_server);

CreateProcess(job_for_child_, std::move(executable), url,
                                       std::move(launch_info), zx::channel(), builder.Build());
                            fdio_spawn_vmo(job.get(), flags, data.vmo().release(), argv.data(),
                                              nullptr, actions.size(), actions.data(),
                                              process.reset_and_get_address(), err_msg);

zx_channel_create(0, &launcher, &launcher_request) 
                                      fdio_service_connect("/svc/fuchsia.process.Launcher", launcher_request);
                                              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);
                                                        建立和process launcher的通道
                                              send_string_array(launcher, fuchsia_process_LauncherAddArgsOrdinal, argv);
                                              send_handles(launcher, handle_capacity, flags, job, action_count, actions, err_msg);
                                              send_namespace(launcher, name_count, name_len, flat, action_count, actions, err_msg);
                                              zx_channel_call(launcher, 0, ZX_TIME_INFINITE, &args,
                                                                                          &actual_bytes, &actual_handles);

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)

fuchsia appmgr分析相关推荐

  1. kali2020.3 vm版本内核是多少_Zircon Fuchsia 内核分析 启动(内核初始化)

    相关阅读: Zircon - Fuchsia 内核分析 - 启动(平台初始化) 简介 前面已经介绍了 Zircon 内核启动的汇编代码部分,主要是一些 CPU 的初始化. 现在 prime CPU 已 ...

  2. Zircon - Fuchsia 内核分析 - 启动(平台初始化)

    简介 Zircon 是 Google 新操作系统 Fuchsia 的内核,基于 LK - Little Kernel 演变而来.而 Little Kernel 前面一直作为 Android 系统的 B ...

  3. 鸿蒙OS与安卓、Fuchsia 对比分析

    本文基础资料来源:https://blog.csdn.net/gxc19971128/article/details/104953294,进行了部分修改完善. 1.三种操作系统比较 对于Android ...

  4. Fuchsia源码分析--系统调用流程

    Fuchsia源码分析--系统调用流程 以zx_channel_create为例 Fuchsia系统调用的定义 Fuchsia系统调用定义文件的编译 Fuchsia系统调用用户空间的调用流程 zx_c ...

  5. Fuchsia X86 kernel启动代码分析

    Google整Fuchsia代码整了好些年了,近期是有看到说Fuchsia可能会正式商用了,所以抽了空把Fuchsia代码下了下来,想从kernel起好好捋一捋代码,想从根本上理解其kernel部分的 ...

  6. Fuchsia - 简析

    一点猜测 Fuchsia 是为了取代 Android 的吗? 我觉得不是的,因为现在 Android 作为移动平台的操作系统已经非常成熟,暂时也没有遇到影响演进的瓶颈,Fuchsia 如果是为了代替 ...

  7. 谷歌新操作系统Fuchsia网站上线,同时支持手机和PC,鼓励开发者参与进来

    铜灵 发自 凹非寺 量子位 出品 | 公众号 QbitAI 备受关注的谷歌新操作系统Fuchsia有了新动态. 有眼尖的网友这两天发现,这个被称作可以同时兼容手机和PC的操作系统,已经悄悄上线了官方网 ...

  8. 3704对象关闭时_JVM 通过逃逸分析就能让对象在栈上分配?没那么简单!

    本文转载自公众号 星哥笔记 作者:Danny姜 校对:承香墨影 经常会有面试官会问一个问题:Java 中的对象都是在"堆"中创建吗? 然后跟求职者大谈特谈「逃逸分析」,说通过「逃逸 ...

  9. python中如何定义颜色_Python图像处理之颜色的定义与使用分析

    本文实例讲述了Python图像处理之颜色的定义与使用.分享给大家供大家参考,具体如下: python中的颜色相关的定义在matplotlib模块中,为方便使用,这里给大家展示一下在这个模块中都定义了哪 ...

最新文章

  1. 小鹏高管:高速自动驾驶明年实现量产
  2. FPGA之道(74)Verilog生成语句
  3. docker停止容器,删除镜像常用指令
  4. C语言-定义与初始化总结
  5. git已有项目修改提交
  6. 最简单java设计模式:抽象工厂模式
  7. 8.5 趣味游戏(2)
  8. C#.Net 如何动态加载与卸载程序集(.dll或者.exe)0-------通过应用程序域AppDomain加载和卸载程序集...
  9. 剑指OFFER之把数组排成最小的数(九度OJ1504)
  10. 微信小程序/js上传图片值腾讯云cos
  11. 很不错的js幻灯片代码分享
  12. r语言和metawin_Meta分析系列之二_Meta分析的软件
  13. 150页的剑指Offer解答PDF,它来了!!!
  14. 简历表格下载word格式 免费版​
  15. Java毕业设计-快递物流管理系统
  16. 深入浅出CChart 每日一课——快乐高四第二十课 七月流火,总复习之CChart多种编程模式
  17. 用AutoIt写网页外挂系列之 开心网的X世界网页游戏自动送免费礼物
  18. ArcEngine中的ICommand和ITool
  19. JAVAOooooo。。。。。ooo0000OOOOO
  20. 短网址生成+域名检测+短网址还原+域名防红四合一前端源码

热门文章

  1. 在html中写for循环表格trtd,嵌套的HTML表格在javascript for循环
  2. GameFrameWork框架(Unity3D)使用笔记(八) 实现场景加载进度条
  3. 我为什么说【直播电商】是第三代电商?
  4. 辅警是事业编制吗?辅警会纳入事业编制吗?
  5. Cadence Allegro解散Group组图文教程及视频演示
  6. VC中的所有WM消息
  7. 学习HTML+CSS知识点
  8. html+css实现京东、英雄联盟静态页面
  9. word如何批量更改公式字体
  10. chrome浏览器一键切换搜索引擎,一键切换谷歌和百度搜索(不需要重新输入keyword,带关键词切换引擎)