runprocess()
in gecko/ipc/glue/ProcessUtils_linux.cpp tell us how B2G works:
/**
* How does B2G Loader Work?
*
* <<parent process>> <<child process>>
* ProcLoaderParent -----> ProcLoaderChild
* ^ |
* | load() | content_process_main()
* | V
* ProcLoaderClient Nuwa/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.
*
* 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.
*/
gecko/b2g/app/B2GLoader.cpp
main(int argc, const char* argv[]) --->
return RunProcesses(argc, argv, reservedFds) --->
XRE_ProcLoaderClientInit(pid_t aPeerPid, int aChannelFd, FdArray& aReservedFds) --->
mozilla::ipc::ProcLoaderClientInit(aPeerPid, aChannelFd) 对client端(b2g process)进行初始化,,设置几个值。如下:
gecko/ipc/glue/ProcessUtils_linux.cpp
static void
CloseFileDescriptors(FdArray& aFds)
{
for (size_t i = 0; i < aFds.length(); i++) {
unused << HANDLE_EINTR(close(aFds[i]));
}
}
/**
* 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 void
ProcLoaderClientInit(pid_t aPeerPid, int aChannelFd)
{
MOZ_ASSERT(!sProcLoaderClientInitialized, "call ProcLoaderClientInit() more than once");
MOZ_ASSERT(aPeerPid != 0 && aChannelFd != -1, "invalid argument");
sProcLoaderPid = aPeerPid;
sProcLoaderChannelFd = aChannelFd;
sProcLoaderClientInitialized = true;
}
/**
* Initialize the client of B2G loader for Gecko.
*/
void
ProcLoaderClientGeckoInit()
{
MOZ_ASSERT(sProcLoaderClientInitialized, "call ProcLoaderClientInit() at first");
MOZ_ASSERT(!sProcLoaderClientGeckoInitialized,
"call ProcLoaderClientGeckoInit() more than once");
if (!Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false)) {
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);
sProcLoaderParent = new ProcLoaderParent();
sProcLoaderParent->Open(transport,
sProcLoaderPid,
XRE_GetIOMessageLoop(),
ParentSide);
sProcLoaderLoop = MessageLoop::current();
}
bool ProcLoaderIsInitialized()
{
return sProcLoaderPid != 0;
}
#ifdef MOZ_B2G_LOADER
void
XRE_ProcLoaderClientInit(pid_t aPeerPid, int aChannelFd, FdArray& aReservedFds)
{
// We already performed fork(). It's safe to free the "danger zone" of file
// descriptors .
mozilla::ipc::CloseFileDescriptors(aReservedFds);
mozilla::ipc::ProcLoaderClientInit(aPeerPid, aChannelFd);
}
int
XRE_ProcLoaderServiceRun(pid_t aPeerPid, int aFd,
int aArgc, const char *aArgv[],
FdArray& aReservedFds)
{
return mozilla::ipc::ProcLoaderServiceRun(aPeerPid, aFd,
aArgc, aArgv,
aReservedFds);
}
#endif /* MOZ_B2G_LOADER */
main(int argc, const char* argv[]) --->
RunProcesses(argc, argv, reservedFds) --->
XRE_ProcLoaderClientInit(pid_t aPeerPid, int aChannelFd, FdArray& aReservedFds) --->
mozilla::ipc::ProcLoaderClientInit(aPeerPid, aChannelFd)这条线是初始化b2g loader的第一阶段,
主要目的是从b2gloader的main中获取child的信息(即将参数传下来)。b2gloader的初始化的第二阶段大体是将
获取的这些child的参数去初始化gecko 同时使得loader的client 端就绪。
main(int argc, const char* argv[]) --->
return RunProcesses(argc, argv, reservedFds) --->
return XRE_ProcLoaderServiceRun(getppid(), childSock, argc, argv, aReservedFds) --->
return mozilla::ipc::ProcLoaderServiceRun(aPeerPid, aFd, aArgc, aArgv,aReservedFds);
/**
* 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 int
ProcLoaderServiceRun(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).
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;
}
b2g_main
XRE_main之前xpcom框架已经初始化结束了?是在loadstaicdata 模块下完成的吗?因为直接do_Getservice()了?