|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "nsXULAppAPI.h" |
|
7 #include "application.ini.h" |
|
8 #include "nsXPCOMGlue.h" |
|
9 #if defined(XP_WIN) |
|
10 #include <windows.h> |
|
11 #include <stdlib.h> |
|
12 #elif defined(XP_UNIX) |
|
13 #include <sys/time.h> |
|
14 #include <sys/resource.h> |
|
15 #include <unistd.h> |
|
16 #endif |
|
17 |
|
18 #include <stdio.h> |
|
19 #include <stdarg.h> |
|
20 |
|
21 #include "nsCOMPtr.h" |
|
22 #include "nsIFile.h" |
|
23 #include "nsStringGlue.h" |
|
24 |
|
25 #ifdef XP_WIN |
|
26 // we want a wmain entry point |
|
27 #include "nsWindowsWMain.cpp" |
|
28 #define snprintf _snprintf |
|
29 #define strcasecmp _stricmp |
|
30 #endif |
|
31 |
|
32 #ifdef MOZ_WIDGET_GONK |
|
33 #include "GonkDisplay.h" |
|
34 #endif |
|
35 |
|
36 #include "BinaryPath.h" |
|
37 |
|
38 #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL |
|
39 |
|
40 #ifdef MOZ_WIDGET_GONK |
|
41 # include <binder/ProcessState.h> |
|
42 #endif |
|
43 |
|
44 #include "mozilla/Telemetry.h" |
|
45 #include "mozilla/WindowsDllBlocklist.h" |
|
46 |
|
47 static void Output(const char *fmt, ... ) |
|
48 { |
|
49 va_list ap; |
|
50 va_start(ap, fmt); |
|
51 |
|
52 #if defined(XP_WIN) && !MOZ_WINCONSOLE |
|
53 char16_t msg[2048]; |
|
54 _vsnwprintf(msg, sizeof(msg)/sizeof(msg[0]), NS_ConvertUTF8toUTF16(fmt).get(), ap); |
|
55 MessageBoxW(nullptr, msg, L"XULRunner", MB_OK | MB_ICONERROR); |
|
56 #else |
|
57 vfprintf(stderr, fmt, ap); |
|
58 #endif |
|
59 |
|
60 va_end(ap); |
|
61 } |
|
62 |
|
63 /** |
|
64 * Return true if |arg| matches the given argument name. |
|
65 */ |
|
66 static bool IsArg(const char* arg, const char* s) |
|
67 { |
|
68 if (*arg == '-') |
|
69 { |
|
70 if (*++arg == '-') |
|
71 ++arg; |
|
72 return !strcasecmp(arg, s); |
|
73 } |
|
74 |
|
75 #if defined(XP_WIN) |
|
76 if (*arg == '/') |
|
77 return !strcasecmp(++arg, s); |
|
78 #endif |
|
79 |
|
80 return false; |
|
81 } |
|
82 |
|
83 /** |
|
84 * A helper class which calls NS_LogInit/NS_LogTerm in its scope. |
|
85 */ |
|
86 class ScopedLogging |
|
87 { |
|
88 public: |
|
89 ScopedLogging() { NS_LogInit(); } |
|
90 ~ScopedLogging() { NS_LogTerm(); } |
|
91 }; |
|
92 |
|
93 XRE_GetFileFromPathType XRE_GetFileFromPath; |
|
94 XRE_CreateAppDataType XRE_CreateAppData; |
|
95 XRE_FreeAppDataType XRE_FreeAppData; |
|
96 XRE_TelemetryAccumulateType XRE_TelemetryAccumulate; |
|
97 XRE_mainType XRE_main; |
|
98 |
|
99 static const nsDynamicFunctionLoad kXULFuncs[] = { |
|
100 { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, |
|
101 { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, |
|
102 { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, |
|
103 { "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate }, |
|
104 { "XRE_main", (NSFuncPtr*) &XRE_main }, |
|
105 { nullptr, nullptr } |
|
106 }; |
|
107 |
|
108 static int do_main(int argc, char* argv[]) |
|
109 { |
|
110 nsCOMPtr<nsIFile> appini; |
|
111 nsresult rv; |
|
112 |
|
113 // Allow firefox.exe to launch XULRunner apps via -app <application.ini> |
|
114 // Note that -app must be the *first* argument. |
|
115 const char *appDataFile = getenv("XUL_APP_FILE"); |
|
116 if (appDataFile && *appDataFile) { |
|
117 rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini)); |
|
118 if (NS_FAILED(rv)) { |
|
119 Output("Invalid path found: '%s'", appDataFile); |
|
120 return 255; |
|
121 } |
|
122 } |
|
123 else if (argc > 1 && IsArg(argv[1], "app")) { |
|
124 if (argc == 2) { |
|
125 Output("Incorrect number of arguments passed to -app"); |
|
126 return 255; |
|
127 } |
|
128 |
|
129 rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini)); |
|
130 if (NS_FAILED(rv)) { |
|
131 Output("application.ini path not recognized: '%s'", argv[2]); |
|
132 return 255; |
|
133 } |
|
134 |
|
135 char appEnv[MAXPATHLEN]; |
|
136 snprintf(appEnv, MAXPATHLEN, "XUL_APP_FILE=%s", argv[2]); |
|
137 if (putenv(appEnv)) { |
|
138 Output("Couldn't set %s.\n", appEnv); |
|
139 return 255; |
|
140 } |
|
141 argv[2] = argv[0]; |
|
142 argv += 2; |
|
143 argc -= 2; |
|
144 } |
|
145 |
|
146 #ifdef MOZ_WIDGET_GONK |
|
147 /* Called to start the boot animation */ |
|
148 (void) mozilla::GetGonkDisplay(); |
|
149 #endif |
|
150 |
|
151 if (appini) { |
|
152 nsXREAppData *appData; |
|
153 rv = XRE_CreateAppData(appini, &appData); |
|
154 if (NS_FAILED(rv)) { |
|
155 Output("Couldn't read application.ini"); |
|
156 return 255; |
|
157 } |
|
158 int result = XRE_main(argc, argv, appData, 0); |
|
159 XRE_FreeAppData(appData); |
|
160 return result; |
|
161 } |
|
162 |
|
163 return XRE_main(argc, argv, &sAppData, 0); |
|
164 } |
|
165 |
|
166 int main(int argc, char* argv[]) |
|
167 { |
|
168 char exePath[MAXPATHLEN]; |
|
169 |
|
170 #ifdef MOZ_WIDGET_GONK |
|
171 // This creates a ThreadPool for binder ipc. A ThreadPool is necessary to |
|
172 // receive binder calls, though not necessary to send binder calls. |
|
173 // ProcessState::Self() also needs to be called once on the main thread to |
|
174 // register the main thread with the binder driver. |
|
175 android::ProcessState::self()->startThreadPool(); |
|
176 #endif |
|
177 |
|
178 nsresult rv = mozilla::BinaryPath::Get(argv[0], exePath); |
|
179 if (NS_FAILED(rv)) { |
|
180 Output("Couldn't calculate the application directory.\n"); |
|
181 return 255; |
|
182 } |
|
183 |
|
184 char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); |
|
185 if (!lastSlash || ((lastSlash - exePath) + sizeof(XPCOM_DLL) + 1 > MAXPATHLEN)) |
|
186 return 255; |
|
187 |
|
188 strcpy(++lastSlash, XPCOM_DLL); |
|
189 |
|
190 #if defined(XP_UNIX) |
|
191 // If the b2g app is launched from adb shell, then the shell will wind |
|
192 // up being the process group controller. This means that we can't send |
|
193 // signals to the process group (useful for profiling). |
|
194 // We ignore the return value since setsid() fails if we're already the |
|
195 // process group controller (the normal situation). |
|
196 (void)setsid(); |
|
197 #endif |
|
198 |
|
199 int gotCounters; |
|
200 #if defined(XP_UNIX) |
|
201 struct rusage initialRUsage; |
|
202 gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage); |
|
203 #elif defined(XP_WIN) |
|
204 IO_COUNTERS ioCounters; |
|
205 gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); |
|
206 #endif |
|
207 |
|
208 #ifdef HAS_DLL_BLOCKLIST |
|
209 DllBlocklist_Initialize(); |
|
210 #endif |
|
211 |
|
212 // We do this because of data in bug 771745 |
|
213 XPCOMGlueEnablePreload(); |
|
214 |
|
215 rv = XPCOMGlueStartup(exePath); |
|
216 if (NS_FAILED(rv)) { |
|
217 Output("Couldn't load XPCOM.\n"); |
|
218 return 255; |
|
219 } |
|
220 // Reset exePath so that it is the directory name and not the xpcom dll name |
|
221 *lastSlash = 0; |
|
222 |
|
223 rv = XPCOMGlueLoadXULFunctions(kXULFuncs); |
|
224 if (NS_FAILED(rv)) { |
|
225 Output("Couldn't load XRE functions.\n"); |
|
226 return 255; |
|
227 } |
|
228 |
|
229 if (gotCounters) { |
|
230 #if defined(XP_WIN) |
|
231 XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS, |
|
232 int(ioCounters.ReadOperationCount)); |
|
233 XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_TRANSFER, |
|
234 int(ioCounters.ReadTransferCount / 1024)); |
|
235 IO_COUNTERS newIoCounters; |
|
236 if (GetProcessIoCounters(GetCurrentProcess(), &newIoCounters)) { |
|
237 XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_READ_OPS, |
|
238 int(newIoCounters.ReadOperationCount - ioCounters.ReadOperationCount)); |
|
239 XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_READ_TRANSFER, |
|
240 int((newIoCounters.ReadTransferCount - ioCounters.ReadTransferCount) / 1024)); |
|
241 } |
|
242 #elif defined(XP_UNIX) |
|
243 XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_HARD_FAULTS, |
|
244 int(initialRUsage.ru_majflt)); |
|
245 struct rusage newRUsage; |
|
246 if (!getrusage(RUSAGE_SELF, &newRUsage)) { |
|
247 XRE_TelemetryAccumulate(mozilla::Telemetry::GLUESTARTUP_HARD_FAULTS, |
|
248 int(newRUsage.ru_majflt - initialRUsage.ru_majflt)); |
|
249 } |
|
250 #endif |
|
251 } |
|
252 |
|
253 int result; |
|
254 { |
|
255 ScopedLogging log; |
|
256 result = do_main(argc, argv); |
|
257 } |
|
258 |
|
259 return result; |
|
260 } |