1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=2 autoindent cindent expandtab: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsXULAppAPI.h"
8 #include "application.ini.h"
9 #include "nsXPCOMGlue.h"
10 #include "nsStringGlue.h"
13 #include "BinaryPath.h"
14 #include "nsAutoPtr.h"
20 #include <sys/types.h>
21 #include <sys/socket.h>
25 #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
27 #define ASSERT(x) if (!(x)) { MOZ_CRASH(); }
29 // Functions being loaded by XPCOMGlue
30 XRE_ProcLoaderServiceRunType XRE_ProcLoaderServiceRun
;
31 XRE_ProcLoaderClientInitType XRE_ProcLoaderClientInit
;
32 XRE_ProcLoaderPreloadType XRE_ProcLoaderPreload
;
33 extern XRE_CreateAppDataType XRE_CreateAppData
;
34 extern XRE_GetFileFromPathType XRE_GetFileFromPath
;
36 static const nsDynamicFunctionLoad kXULFuncs
[] = {
37 { "XRE_ProcLoaderServiceRun", (NSFuncPtr
*) &XRE_ProcLoaderServiceRun
},
38 { "XRE_ProcLoaderClientInit", (NSFuncPtr
*) &XRE_ProcLoaderClientInit
},
39 { "XRE_ProcLoaderPreload", (NSFuncPtr
*) &XRE_ProcLoaderPreload
},
40 { "XRE_CreateAppData", (NSFuncPtr
*) &XRE_CreateAppData
},
41 { "XRE_GetFileFromPath", (NSFuncPtr
*) &XRE_GetFileFromPath
},
45 typedef mozilla::Vector
<int> FdArray
;
46 static const int kReservedFileDescriptors
= 5;
47 static const int kBeginReserveFileDescriptor
= STDERR_FILENO
+ 1;
50 GetDirnameSlash(const char *aPath
, char *aOutDir
, int aMaxLen
)
52 char *lastSlash
= strrchr(aPath
, XPCOM_FILE_PATH_SEPARATOR
[0]);
53 if (lastSlash
== nullptr) {
56 int cpsz
= lastSlash
- aPath
+ 1; // include slash
57 if (aMaxLen
<= cpsz
) {
60 strncpy(aOutDir
, aPath
, cpsz
);
66 GetXPCOMPath(const char *aProgram
, char *aOutPath
, int aMaxLen
)
68 nsAutoArrayPtr
<char> progBuf(new char[aMaxLen
]);
69 nsresult rv
= mozilla::BinaryPath::Get(aProgram
, progBuf
);
70 NS_ENSURE_SUCCESS(rv
, false);
72 int len
= GetDirnameSlash(progBuf
, aOutPath
, aMaxLen
);
73 NS_ENSURE_TRUE(!!len
, false);
75 NS_ENSURE_TRUE((len
+ sizeof(XPCOM_DLL
)) < (unsigned)aMaxLen
, false);
76 char *afterSlash
= aOutPath
+ len
;
77 strcpy(afterSlash
, XPCOM_DLL
);
82 LoadLibxul(const char *aXPCOMPath
)
86 XPCOMGlueEnablePreload();
87 rv
= XPCOMGlueStartup(aXPCOMPath
);
88 NS_ENSURE_SUCCESS(rv
, false);
90 rv
= XPCOMGlueLoadXULFunctions(kXULFuncs
);
91 NS_ENSURE_SUCCESS(rv
, false);
97 * Return true if |arg| matches the given argument name.
100 IsArg(const char* arg
, const char* s
)
106 return !strcasecmp(arg
, s
);
111 return !strcasecmp(++arg
, s
);
118 static already_AddRefed
<nsIFile
>
119 GetAppIni(int argc
, const char *argv
[])
121 nsCOMPtr
<nsIFile
> appini
;
124 // Allow firefox.exe to launch XULRunner apps via -app <application.ini>
125 // Note that -app must be the *first* argument.
126 const char *appDataFile
= getenv("XUL_APP_FILE");
127 if (appDataFile
&& *appDataFile
) {
128 rv
= XRE_GetFileFromPath(appDataFile
, getter_AddRefs(appini
));
129 NS_ENSURE_SUCCESS(rv
, nullptr);
130 } else if (argc
> 1 && IsArg(argv
[1], "app")) {
135 rv
= XRE_GetFileFromPath(argv
[2], getter_AddRefs(appini
));
136 NS_ENSURE_SUCCESS(rv
, nullptr);
138 char appEnv
[MAXPATHLEN
];
139 snprintf(appEnv
, MAXPATHLEN
, "XUL_APP_FILE=%s", argv
[2]);
140 if (putenv(appEnv
)) {
145 return appini
.forget();
149 LoadStaticData(int argc
, const char *argv
[])
151 char xpcomPath
[MAXPATHLEN
];
152 bool ok
= GetXPCOMPath(argv
[0], xpcomPath
, MAXPATHLEN
);
153 NS_ENSURE_TRUE(ok
, false);
155 ok
= LoadLibxul(xpcomPath
);
156 NS_ENSURE_TRUE(ok
, false);
158 char progDir
[MAXPATHLEN
];
159 ok
= GetDirnameSlash(xpcomPath
, progDir
, MAXPATHLEN
);
160 NS_ENSURE_TRUE(ok
, false);
162 nsCOMPtr
<nsIFile
> appini
= GetAppIni(argc
, argv
);
163 const nsXREAppData
*appData
;
166 XRE_CreateAppData(appini
, const_cast<nsXREAppData
**>(&appData
));
167 NS_ENSURE_SUCCESS(rv
, false);
172 XRE_ProcLoaderPreload(progDir
, appData
);
175 XRE_FreeAppData(const_cast<nsXREAppData
*>(appData
));
182 * Fork and run parent and child process.
184 * The parent is the b2g process and child for Nuwa.
187 RunProcesses(int argc
, const char *argv
[], FdArray
& aReservedFds
)
190 * The original main() of the b2g process. It is renamed to
191 * b2g_main() for the b2g loader.
193 int b2g_main(int argc
, const char *argv
[]);
195 int ipcSockets
[2] = {-1, -1};
196 int r
= socketpair(AF_LOCAL
, SOCK_STREAM
, 0, ipcSockets
);
198 int parentSock
= ipcSockets
[0];
199 int childSock
= ipcSockets
[1];
201 r
= fcntl(parentSock
, F_SETFL
, O_NONBLOCK
);
203 r
= fcntl(childSock
, F_SETFL
, O_NONBLOCK
);
208 bool isChildProcess
= pid
== 0;
210 close(isChildProcess
? parentSock
: childSock
);
212 if (isChildProcess
) {
213 /* The Nuwa process */
214 /* This provides the IPC service of loading Nuwa at the process.
215 * The b2g process would send a IPC message of loading Nuwa
216 * as the replacement of forking and executing plugin-container.
218 return XRE_ProcLoaderServiceRun(getppid(), childSock
, argc
, argv
,
224 XRE_ProcLoaderClientInit(childPid
, parentSock
, aReservedFds
);
225 return b2g_main(argc
, argv
);
229 * Reserve the file descriptors that shouldn't be taken for other use for the
233 ReserveFileDescriptors(FdArray
& aReservedFds
)
235 for (int i
= 0; i
< kReservedFileDescriptors
; i
++) {
236 struct stat fileState
;
237 int target
= kBeginReserveFileDescriptor
+ i
;
238 if (fstat(target
, &fileState
) == 0) {
239 MOZ_CRASH("ProcLoader error: a magic file descriptor is occupied.");
242 int fd
= open("/dev/null", O_RDWR
);
244 MOZ_CRASH("ProcLoader error: failed to reserve a magic file descriptor.");
247 aReservedFds
.append(target
);
250 // No need to call dup2(). We already occupy the desired file descriptor.
254 if (dup2(fd
, target
)) {
255 MOZ_CRASH("ProcLoader error: failed to reserve a magic file descriptor.");
263 * B2G Loader is responsible for loading the b2g process and the
264 * Nuwa process. It forks into the parent process, for the b2g
265 * process, and the child process, for the Nuwa process.
267 * The loader loads libxul and performs initialization of static data
268 * before forking, so relocation of libxul and static data can be
269 * shared between the b2g process, the Nuwa process, and the content
273 main(int argc
, const char* argv
[])
276 * Reserve file descriptors before loading static data.
279 ReserveFileDescriptors(reservedFds
);
282 * Before fork(), libxul and static data of Gecko are loaded for
285 bool ok
= LoadStaticData(argc
, argv
);
290 return RunProcesses(argc
, argv
, reservedFds
);