一.概述
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
// 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
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->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
[this](fidl::InterfaceRequest
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
我们先看这个函数调用,
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
返回h2
ServiceProviderBridge::AddBinding(h2)
bindings_.AddBinding(this, std::move(request))
this是ServiceProviderBridge自己 ImplPtr=ServiceProviderBridge*
Binding(impl, request)
Binding(std::forward
impl_(std::forward
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::Proxy_处理,另一头给了ServiceProviderBridge添加binding,监听上
service_provider.get()
返回impl里的ServiceProvider::Proxy_ 它继承了ServiceProvider
下面这个ConnectToService的定义在connect.h里
loader_ = ConnectToService
这里service_provider是ServiceProvider::Proxy_
InterfacePtr
先看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
上面这段代码的含义就是通过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->Serve();
wait_.set_object(channel_.get());
wait_.Begin(vfs_->async());
run_sysmgr()
fuchsia::sys::LaunchInfo launch_info;
LaunchInfo是fidl生成的, launcher.fidl
sysmgr.NewRequest() InterfacePtr
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)