它们通信的目的在于:
b2g要发消息给nuwa,让它fork出web app进程。它们发生在nuwa进程已经完全启动,并准备好fork 其他app子进程。猜想,用的是socket pair 建立关系,ipdl(最终用的是共享内存读写)进行线程级别的信息交互。socket pair只是用于建立通道???
nuwa的操作,从b2g开始fork出两个进程之后,兵分两路,nuwa进程完成自己的所有初始化(包括哪些?)且一直在等待b2g的加载新进程的消息。b2g也一路走下去,完成初始化等,并在appstartup 请求nuwa加载新进程。
具体通信:
/*** How does B2G Loader Work?** <<parent process>><<child process>>* ProcLoaderParent -----> ProcLoaderChild* ^ |* | load()| content_process_main()* | V*ProcLoaderClientNuwa/plugin-container* ^* | ProcLoaderLoad()* ...*ContentParent*** B2G loader includes an IPC protocol PProcLoader for communication* between client (parent) and server (child). The b2g process is the* client. It requests the server to load/start the Nuwa process with* the given arguments, env variables, and file descriptors.** ProcLoaderClientInit() is called by B2G loader to initialize the* client side, the b2g process. Then the b2g_main() is called to* start b2g process.** ProcLoaderClientGeckoInit() is called by XRE_main() to create the* parent actor, |ProcLoaderParent|, of PProcLoader for servicing the* request to run Nuwa process later once Gecko has been initialized.*创建parent actor 用于请求nuwa加载进程* ProcLoaderServiceRun() is called by the server process. It starts* an IOThread and event loop to serve the |ProcLoaderChild|* implmentation of PProcLoader protocol as the child actor. Once it* recieves a load() request, it stops the IOThread and event loop,* then starts running the main function of the content process with* the given arguments.** NOTE: The server process serves at most one load() request.*/
#include "mozilla/ipc/PProcLoaderParent.h"
#include "mozilla/ipc/PProcLoaderChild.h"
gecko/ipc/glue/ProcessUtils_linux.cpp
前b2g:
以上数据函数库等完全准备好了。
完毕之后就开始:
main --> return RunProcesses(argc, argv, reservedFds)
开始fork后分出两个进程进行工作。
nuwa process:
main ->RunProcesses->XRE_ProcLoaderServiceRun -> mozilla::ipc::ProcLoaderServiceRun(aPeerPid:180, aFd:14,aArgc:1, aArgv[...0]:/system/b2g/b2g,aReservedFds[...0]:3)
RunProcesses->XRE_ProcLoaderServiceRun->ProcLoaderServiceRun->
(1XRE_InitCommandLine->XRE_GetBinaryPath(aArgv:/system/b2g/b2g)
(2process= new ContentProcess(aPeerPid:179)--->
ChildThread *iothread = process->child_thread();
(3new ProcLoaderChild(aPeerPid:179)->iothread->message_loop()
ProcLoaderChild *loaderChild = new ProcLoaderChild(aPeerPid)
loaderChild->Open(transport, aPeerPid, iothread->message_loop())
ProcessChild::ProcessChild(ProcessId aParentPid)
: ChildProcess(new IOThreadChild())
, mUILoop(MessageLoop::current())
, mParentPid(aParentPid)
{ ... }
(4BackgroundHangMonitor::Prohibit()
(5loop.Run();
(6 BackgroundHangMonitor::Allow();
(7 XRE_DeinitCommandLine();
(8 int ret = task->DoWork()->int ret = content_process_main(argc, argv)
RunProcesses开始,
nuwa 进程被fork 出来,去执行XRE_ProcLoaderServiceRun->ProcLoaderServiceRun call XRE_InitCommandLine--->
Fuc:RunProcesses ### pid >0 is parentSock(Pid of childSock), or 0 is return by childSock:0
Fuc:RunProcesses ### pid=0,|pid='0',it is childprocess|, isChildProcess=1
Fuc:RunProcesses close parentSock,in nuwa(child) process
Fuc:RunProcesses call XRE_ProcLoaderServiceRun--->
Fuc:RunProcesses XRE_ProcLoaderServiceRun(getppid():181, childSock:14, argc:1, argv:/system/b2g/b2g,aReservedFds[...0]:3)
ipc/glue/ProcessUtils_linux.cpp:672, Fuc:XRE_ProcLoaderServiceRun ----------------------------------
ipc/glue/ProcessUtils_linux.cpp:673, Fuc:XRE_ProcLoaderServiceRun .==nuwa process==. XRE_ProcLoaderServiceRun call mozilla::ipc::ProcLoaderServiceRun(aPeerPid:181, aFd:14,aArgc:1, aArgv[...0]:/system/b2g/b2g,aReservedFds[...0]:3)
ipc/glue/ProcessUtils_linux.cpp:577, Fuc:ProcLoaderServiceRun ----------------------------------
ipc/glue/ProcessUtils_linux.cpp:588, Fuc:ProcLoaderServiceRun aArgv[i]:/system/b2g/b2g
ipc/glue/ProcessUtils_linux.cpp:597, Fuc:ProcLoaderServiceRun call XRE_InitCommandLine--->b2g ,nuwa都要来执行这个模块,为了getbinarypath 二进制可执行文件的地址?
cpp:4583, Fuc:XRE_InitCommandLine ----------------------------------
nuwa 进程被fork 出来,去执行XRE_ProcLoaderServiceRun->ProcLoaderServiceRun ->XRE_InitCommandLine--->
XRE_ProcLoaderServiceRun传入b2g的pid,child的sock 号,就直接去初始化XRE_InitCommandLine,
Fuc:XRE_InitCommandLine XRE_GetBinaryPath(aArgv:/system/b2g/b2g)--->//一样,获取地址
rocessUtils_linux.cpp:610, Fuc:ProcLoaderServiceRun new ContentProcess(aPeerPid:181)--->
rocessChild.cpp:46, Fuc:ProcessChild >>>>>>>>>>>>>>>>>>>>>>>>>>>st.func
rocessUtils_linux.cpp:615, Fuc:ProcLoaderServiceRun new ProcLoaderChild(aPeerPid:181)--->//传入b2g的进程pid,是直接复制b2g一模一样的资源吗?
rocessUtils_linux.cpp:619, Fuc:ProcLoaderServiceRun loaderChild->Open(transport, aPeerPid, iothread->message_loop())//加载子进程并打开,io线程执行message_loop,并与b2g进程进行传输消息?
rocessUtils_linux.cpp:621, Fuc:ProcLoaderServiceRun call BackgroundHangMonitor::Prohibit()--->//禁止后台挂起监控
rocessUtils_linux.cpp:625, Fuc:ProcLoaderServiceRun call loop.Run--->//循环运行
/**
* Run service of ProcLoader.//开启进程加载器的服务端,一直在那里运行,传入参数就是b2g进程的pid,以及socket的文件描述符(父进程的?不对是childSock:14,)
*
* \param aPeerPid is the pid of the parent.
* \param aFd is the file descriptor of the socket for IPC.
*
* See the comment near the head of this file.
*/
static int
ProcLoaderServiceRun(pid_t aPeerPid, int aFd,
int aArgc, const char *aArgv[],
FdArray& aReservedFds)
{
...
}
///
//
b2g process:
1.
1.1main ->RunProcesses->XRE_ProcLoaderClientInit->ProcLoaderClientInit//初始化client 端,各数据供后与nuwa通信用
XRE_ProcLoaderClientInit call mozilla::ipc::ProcLoaderClientInit(aPeerPid:556, aChannelFd:13)
ProcLoaderClientInit sProcLoaderPid:556,sProcLoaderChannelFd:13,sProcLoaderClientInitialized:true
初始化这些数据,供后面nuwa 与b2g 通信时建立连接等。
1.2main ->RunProcesses->b2g_main -> startThreadPool--->//共享线程池
1.3main ->RunProcesses->b2g_main ->XPCOMGlueLoadXULFunctions //再次加载GlueLoadXUL函数
抓重点!!!别看些细枝末节的东西。
1.4b2g_main->do_main -> StartBootAnimation--->//开机动画
1.5main ->RunProcesses->b2g_main -> do_main--->XRE_main
b2g_main->do_main -> XRE_main--->XRE_main::XRE_main()->:
b2g_main->do_main-> XRE_main--->XRE_main::XRE_main()-> XRE_mainInit--->mDirProvider.Initialize-->//初始化目录服务
XRE_mainInit -> XRE_InitCommandLine()-->//xre 主初始化命令行,
XRE_main::XRE_main()-> XRE_mainStartup--->//主启动,版本创建
ScopedXPCOMStartup::Initialize()
XRE_main::XRE_main()->rv = mScopedXPCOM->Initialize()--->NS_InitXPCOM2-->//初始化并启动xpcom等
fork分开之初:
main() ->RunProcesses fork 出2进程后:
main() ->RunProcesses->b2g_main -> XPCOMGlueLoadXULFunctions 不厌其烦地废话!!!
XPCOMGlueLoadXULFunctions 就加载些函数,并不是重点,过。
中间分析:b2g -> nuwa 猜想假设等
RunProcesses XRE_ProcLoaderClientInit(childPid:530, parentSock:13, aReservedFds[...0]:3)
ProcLoaderClientGeckoInit sProcLoaderParent = new ProcLoaderParent()
RunProcesses XRE_ProcLoaderServiceRun(getppid():181, childSock:14, argc:1, argv:/system/b2g/b2g,aReservedFds[...0]:3)
ProcLoaderServiceRun new ContentProcess(aPeerPid:181)--->,
new ProcLoaderChild(aPeerPid:181)
在b2g 和nuwa之间,起触发因素的似乎是appstartup,猜想,是appstartup 提交了启动应用的请求,b2g发消息给nuwa,nuwa结束目前循环,加载出来一个进程(对应一个上层应用),然后把它丢到后台,继续回来接活,直到又有新应用向b2g发请求,说”给我拉起一个进程,让这家伙跑“,nuwa接到活后快乐的去把它拉起来,丢到后台,然后继续出来接活,反反复复。
nuwa其实就是一个进程生产器,生产出来就丢出去,至于它们跟b2g的通信,或者进程和进程之间的通信,应该是它们自己解决,如何呢?ipdl如何运作?以及猜想是否正确,待验证。
b2g总模块:
gecko/toolkit/xre/nsAppRunner.cpp:4569, Fuc:XRE_main >>>>>>>>>>>>>>>>>>>>>>>>>>>st.func
重点分析XRE_main:
结构:
前3个稍微了解即可,初始化启动些必要的东西。简言之,准备数据,数据丢进运行功能模块运行。
NS_InitXPCOM2重点分析:b2g process
b2g process NS_InitXPCOM2部分Log分析:
启动app(nuwa)进程 部分:
较完整版XRE_mainRun
nuwa部分分析:
完整的nuwa process 端Log分析:
b2g 叫相关模块Load nuwa 以及之后,混杂b2g 和nuwa 进程
两进程交互部分:
RunProcesses -> XRE_ProcLoaderClientInit--->//初始化client端,传入nuwa进程的pid,fd,parent sock等
在前面初始化client的时候,ProcLoaderClientInit sProcLoaderPid:530,sProcLoaderChannelFd:13,sProcLoaderClientInitialized:true
这里搞定之后就开始进入b2g_main了,
与上层应用联系的地方?gecko/widget/gonk/nsAppShell.cpp
进程间:
#include "mozilla/ipc/PProcLoaderParent.h"
#include "mozilla/ipc/PProcLoaderChild.h"
gecko/ipc/glue/ProcessUtils_linux.cpp
/*** Initialize the client of B2G loader for loader itself.** The initialization of B2G loader are divided into two stages. First* stage is to collect child info passed from the main program of the* loader. Second stage is to initialize Gecko according to info from the* first stage and make the client of loader service ready.** \param aPeerPid is the pid of the child.* \param aChannelFd is the file descriptor of the socket used for IPC.*/static voidProcLoaderClientInit(pid_t aPeerPid, int aChannelFd){P_LOGI(SEPARATOR_LINE );MOZ_ASSERT(!sProcLoaderClientInitialized, "call ProcLoaderClientInit() more than once");MOZ_ASSERT(aPeerPid != 0 && aChannelFd != -1, "invalid argument");sProcLoaderPid = aPeerPid;sProcLoaderChannelFd = aChannelFd;sProcLoaderClientInitialized = true;P_LOGI("sProcLoaderPid:%d,sProcLoaderChannelFd:%d,sProcLoaderClientInitialized:true",sProcLoaderPid,sProcLoaderChannelFd);}/*** Initialize the client of B2G loader for Gecko.*/voidProcLoaderClientGeckoInit(){P_LOGI(SEPARATOR_LINE );MOZ_ASSERT(sProcLoaderClientInitialized, "call ProcLoaderClientInit() at first");MOZ_ASSERT(!sProcLoaderClientGeckoInitialized,"call ProcLoaderClientGeckoInit() more than once");if (!Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false)) {P_LOGI(" call kill(sProcLoaderPid, SIGKILL)");kill(sProcLoaderPid, SIGKILL);sProcLoaderPid = 0;close(sProcLoaderChannelFd);sProcLoaderChannelFd = -1;return;}sProcLoaderClientGeckoInitialized = true;TransportDescriptor fd;fd.mFd = base::FileDescriptor(sProcLoaderChannelFd, /*auto_close=*/ false);sProcLoaderChannelFd = -1;Transport *transport = OpenDescriptor(fd, Transport::MODE_CLIENT);P_LOGI(" sProcLoaderParent = new ProcLoaderParent()");sProcLoaderParent = new ProcLoaderParent();P_LOGI("sProcLoaderParent->Open(transport,sProcLoaderPid,XRE_GetIOMessageLoop(),ParentSide) ");sProcLoaderParent->Open(transport,sProcLoaderPid,XRE_GetIOMessageLoop(),ParentSide);P_LOGI("call sProcLoaderLoop = MessageLoop::current()--->");sProcLoaderLoop = MessageLoop::current();}/*** Request the loader service, the server, to load Nuwa.*/boolProcLoaderLoad(const char *aArgv[],const char *aEnvp[],const file_handle_mapping_vector &aFdsRemap,const ChildPrivileges aPrivs,ProcessHandle *aProcessHandle){P_LOGI(SEPARATOR_LINE );static int cookie=0;int i;if (sProcLoaderParent == nullptr || sProcLoaderPid == 0) {return false;}AsyncSendLoadData *load = new AsyncSendLoadData();nsTArray<nsCString> &argv = load->mArgv;for (i = 0; aArgv[i] != nullptr; i++) {argv.AppendElement(nsCString(aArgv[i]));}nsTArray<nsCString> &env = load->mEnv;for (i = 0; aEnvp[i] != nullptr; i++) {env.AppendElement(nsCString(aEnvp[i]));}nsTArray<FDRemap> &fdsremap = load->mFdsremap;for (file_handle_mapping_vector::const_iterator fdmap =aFdsRemap.begin();fdmap != aFdsRemap.end();fdmap++) {fdsremap.AppendElement(FDRemap(FileDescriptor(fdmap->first), fdmap->second));}load->mPrivs = aPrivs;load->mCookie = cookie++;*aProcessHandle = sProcLoaderPid;sProcLoaderPid = 0;sProcLoaderLoop->PostTask(FROM_HERE,NewRunnableFunction(AsyncSendLoad, load));return true;}/*** Run service of ProcLoader.** \param aPeerPid is the pid of the parent.* \param aFd is the file descriptor of the socket for IPC.** See the comment near the head of this file.*/static intProcLoaderServiceRun(pid_t aPeerPid, int aFd,int aArgc, const char *aArgv[],FdArray& aReservedFds){P_LOGI(SEPARATOR_LINE );// Make a copy of aReservedFds. It will be used when we dup() the magic file// descriptors when ProcLoaderChild::RecvLoad() runs.sReservedFds = MakeUnique<FdArray>(mozilla::Move(aReservedFds));ScopedLogging logging;char **_argv;_argv = new char *[aArgc + 1];for (int i = 0; i < aArgc; i++) {_argv[i] = ::strdup(aArgv[i]);P_LOGI("aArgv[i]:%s",_argv[i]);MOZ_ASSERT(_argv[i] != nullptr);}_argv[aArgc] = nullptr;gArgv = _argv;gArgc = aArgc;{P_LOGI("call XRE_InitCommandLine--->");nsresult rv = XRE_InitCommandLine(aArgc, _argv);if (NS_FAILED(rv)) {MOZ_CRASH();}TransportDescriptor fd;fd.mFd = base::FileDescriptor(aFd, /*auto_close =*/false);MOZ_ASSERT(!sProcLoaderServing);MessageLoop loop;nsAutoPtr<ContentProcess> process;P_LOGI("new ContentProcess(aPeerPid:%d)--->",aPeerPid);process = new ContentProcess(aPeerPid);ChildThread *iothread = process->child_thread();Transport *transport = OpenDescriptor(fd, Transport::MODE_CLIENT);P_LOGI("new ProcLoaderChild(aPeerPid:%d)--->",aPeerPid);ProcLoaderChild *loaderChild = new ProcLoaderChild(aPeerPid);// Pass a message loop to initialize (connect) the channel// (connection).P_LOGI(" loaderChild->Open(transport, aPeerPid, iothread->message_loop())");loaderChild->Open(transport, aPeerPid, iothread->message_loop());P_LOGI("call BackgroundHangMonitor::Prohibit()--->");BackgroundHangMonitor::Prohibit();sProcLoaderServing = true;P_LOGI("call loop.Run--->");loop.Run();P_LOGI("call BackgroundHangMonitor::Allow()--->");BackgroundHangMonitor::Allow();P_LOGI("call XRE_DeinitCommandLine--->");XRE_DeinitCommandLine();}MOZ_ASSERT(sProcLoaderDispatchedTask != nullptr);ProcLoaderRunnerBase *task = sProcLoaderDispatchedTask;sProcLoaderDispatchedTask = nullptr;P_LOGI("call task->DoWork()--->");int ret = task->DoWork();delete task;for (int i = 0; i < aArgc; i++) {free(_argv[i]);}delete[] _argv;return ret;}#ifdef MOZ_B2G_LOADERvoidXRE_ProcLoaderClientInit(pid_t aPeerPid, int aChannelFd, FdArray& aReservedFds){P_LOGI(SEPARATOR_LINE );// We already performed fork(). It's safe to free the "danger zone" of file// descriptors .mozilla::ipc::CloseFileDescriptors(aReservedFds);P_LOGI(".==b2g process==. XRE_ProcLoaderClientInit call mozilla::ipc::ProcLoaderClientInit(aPeerPid:%d, aChannelFd:%d)",aPeerPid, aChannelFd);mozilla::ipc::ProcLoaderClientInit(aPeerPid, aChannelFd);}intXRE_ProcLoaderServiceRun(pid_t aPeerPid, int aFd,int aArgc, const char *aArgv[],FdArray& aReservedFds){P_LOGI(SEPARATOR_LINE );P_LOGI(".==nuwa process==. XRE_ProcLoaderServiceRun call mozilla::ipc::ProcLoaderServiceRun(aPeerPid:%d, aFd:%d,aArgc:%d, aArgv[...0]:%s,aReservedFds[...0]:%d)",aPeerPid, aFd,aArgc, aArgv[0],aReservedFds[0]);return mozilla::ipc::ProcLoaderServiceRun(aPeerPid, aFd,aArgc, aArgv,aReservedFds);}#endif /* MOZ_B2G_LOADER */
/*** Run service of ProcLoader.** \param aPeerPid is the pid of the parent.* \param aFd is the file descriptor of the socket for IPC.** See the comment near the head of this file.*/static intProcLoaderServiceRun(pid_t aPeerPid, int aFd,int aArgc, const char *aArgv[],FdArray& aReservedFds){P_LOGI(SEPARATOR_LINE );// Make a copy of aReservedFds. It will be used when we dup() the magic file// descriptors when ProcLoaderChild::RecvLoad() runs.sReservedFds = MakeUnique<FdArray>(mozilla::Move(aReservedFds));ScopedLogging logging;char **_argv;_argv = new char *[aArgc + 1];for (int i = 0; i < aArgc; i++) {_argv[i] = ::strdup(aArgv[i]);P_LOGI("aArgv[i]:%s",_argv[i]);MOZ_ASSERT(_argv[i] != nullptr);}_argv[aArgc] = nullptr;gArgv = _argv;gArgc = aArgc;{P_LOGI("call XRE_InitCommandLine--->");nsresult rv = XRE_InitCommandLine(aArgc, _argv);if (NS_FAILED(rv)) {MOZ_CRASH();}TransportDescriptor fd;fd.mFd = base::FileDescriptor(aFd, /*auto_close =*/false);MOZ_ASSERT(!sProcLoaderServing);MessageLoop loop;nsAutoPtr<ContentProcess> process;P_LOGI("new ContentProcess(aPeerPid:%d)--->",aPeerPid);process = new ContentProcess(aPeerPid);ChildThread *iothread = process->child_thread();Transport *transport = OpenDescriptor(fd, Transport::MODE_CLIENT);P_LOGI("new ProcLoaderChild(aPeerPid:%d)--->",aPeerPid);ProcLoaderChild *loaderChild = new ProcLoaderChild(aPeerPid);// Pass a message loop to initialize (connect) the channel// (connection).P_LOGI(" loaderChild->Open(transport, aPeerPid, iothread->message_loop())");loaderChild->Open(transport, aPeerPid, iothread->message_loop());P_LOGI("call BackgroundHangMonitor::Prohibit()--->");BackgroundHangMonitor::Prohibit();sProcLoaderServing = true;P_LOGI("call loop.Run--->");loop.Run();P_LOGI("call BackgroundHangMonitor::Allow()--->");BackgroundHangMonitor::Allow();P_LOGI("call XRE_DeinitCommandLine--->");XRE_DeinitCommandLine();}MOZ_ASSERT(sProcLoaderDispatchedTask != nullptr);ProcLoaderRunnerBase *task = sProcLoaderDispatchedTask;sProcLoaderDispatchedTask = nullptr;P_LOGI("call task->DoWork()--->");int ret = task->DoWork();delete task;for (int i = 0; i < aArgc; i++) {free(_argv[i]);}delete[] _argv;return ret;}
processchild:
gecko/ipc/glue/ProcessChild.cppProcessChild::ProcessChild(ProcessId aParentPid): ChildProcess(new IOThreadChild()), mUILoop(MessageLoop::current()), mParentPid(aParentPid){P_LOGI(STA_LINE);//P_LOGI("ProcessId:%d aParentPid:%d",ProcessId, aParentPid);MOZ_ASSERT(mUILoop, "UILoop should be created by now");MOZ_ASSERT(!gProcessChild, "should only be one ProcessChild");gProcessChild = this;}