|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
|
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 |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "nsStatusReporterManager.h" |
|
8 #include "nsCOMPtr.h" |
|
9 #include "nsDirectoryServiceDefs.h" |
|
10 #include "nsArrayEnumerator.h" |
|
11 #include "nsISimpleEnumerator.h" |
|
12 #include "nsIFile.h" |
|
13 #include "nsDumpUtils.h" |
|
14 #include "nsIFileStreams.h" |
|
15 #include "nsPrintfCString.h" |
|
16 |
|
17 #ifdef XP_WIN |
|
18 #include <process.h> |
|
19 #define getpid _getpid |
|
20 #else |
|
21 #include <unistd.h> |
|
22 #endif |
|
23 |
|
24 #ifdef XP_UNIX |
|
25 #define DO_STATUS_REPORT 1 |
|
26 #endif |
|
27 |
|
28 #ifdef DO_STATUS_REPORT // { |
|
29 namespace { |
|
30 |
|
31 class DumpStatusInfoToTempDirRunnable : public nsRunnable |
|
32 { |
|
33 public: |
|
34 DumpStatusInfoToTempDirRunnable() |
|
35 {} |
|
36 |
|
37 NS_IMETHOD Run() |
|
38 { |
|
39 nsCOMPtr<nsIStatusReporterManager> mgr = |
|
40 do_GetService("@mozilla.org/status-reporter-manager;1"); |
|
41 mgr->DumpReports(); |
|
42 return NS_OK; |
|
43 } |
|
44 }; |
|
45 |
|
46 void doStatusReport(const nsCString& inputStr) |
|
47 { |
|
48 LOG("FifoWatcher(%s) dispatching status report runnable.", inputStr.get()); |
|
49 nsRefPtr<DumpStatusInfoToTempDirRunnable> runnable = |
|
50 new DumpStatusInfoToTempDirRunnable(); |
|
51 NS_DispatchToMainThread(runnable); |
|
52 } |
|
53 |
|
54 } //anonymous namespace |
|
55 #endif // DO_STATUS_REPORT } |
|
56 |
|
57 static bool gStatusReportProgress = 0; |
|
58 static int gNumReporters = 0; |
|
59 |
|
60 nsresult getStatus(nsACString& desc) |
|
61 { |
|
62 if(!gStatusReportProgress) |
|
63 desc.AssignLiteral("Init"); |
|
64 else { |
|
65 desc.AssignLiteral("Running:\nThere are "); |
|
66 desc.AppendInt(gNumReporters); |
|
67 desc.AppendLiteral(" reporters"); |
|
68 } |
|
69 return NS_OK; |
|
70 } |
|
71 |
|
72 NS_STATUS_REPORTER_IMPLEMENT(StatusReporter, "StatusReporter State", getStatus) |
|
73 |
|
74 #define DUMP(o, s) \ |
|
75 do { \ |
|
76 const char* s2 = (s); \ |
|
77 uint32_t dummy; \ |
|
78 nsresult rv = (o)->Write((s2), strlen(s2), &dummy); \ |
|
79 if (NS_WARN_IF(NS_FAILED(rv))) \ |
|
80 return rv; \ |
|
81 } while (0) |
|
82 |
|
83 static nsresult |
|
84 DumpReport(nsIFileOutputStream* aOStream, const nsCString& aProcess, |
|
85 const nsCString& aName, const nsCString& aDescription) |
|
86 { |
|
87 int pid; |
|
88 if (aProcess.IsEmpty()) { |
|
89 pid = getpid(); |
|
90 nsPrintfCString pidStr("PID %u", pid); |
|
91 DUMP(aOStream, "\n {\"Process\": \""); |
|
92 DUMP(aOStream, pidStr.get()); |
|
93 } else { |
|
94 pid = 0; |
|
95 DUMP(aOStream, "\n {\"Unknown Process\": \""); |
|
96 } |
|
97 |
|
98 DUMP(aOStream, "\", \"Reporter name\": \""); |
|
99 DUMP(aOStream, aName.get()); |
|
100 |
|
101 DUMP(aOStream, "\", \"Status Description\": \""); |
|
102 DUMP(aOStream, aDescription.get()); |
|
103 DUMP(aOStream, "\"}"); |
|
104 |
|
105 return NS_OK; |
|
106 } |
|
107 |
|
108 /** |
|
109 ** nsStatusReporterManager implementation |
|
110 **/ |
|
111 |
|
112 NS_IMPL_ISUPPORTS(nsStatusReporterManager, nsIStatusReporterManager) |
|
113 |
|
114 nsStatusReporterManager::nsStatusReporterManager() |
|
115 { |
|
116 } |
|
117 |
|
118 nsStatusReporterManager::~nsStatusReporterManager() |
|
119 { |
|
120 } |
|
121 |
|
122 NS_IMETHODIMP |
|
123 nsStatusReporterManager::Init() |
|
124 { |
|
125 RegisterReporter(new NS_STATUS_REPORTER_NAME(StatusReporter)); |
|
126 gStatusReportProgress = 1; |
|
127 |
|
128 #ifdef DO_STATUS_REPORT |
|
129 if (FifoWatcher::MaybeCreate()) { |
|
130 FifoWatcher* fw = FifoWatcher::GetSingleton(); |
|
131 fw->RegisterCallback(NS_LITERAL_CSTRING("status report"),doStatusReport); |
|
132 } |
|
133 #endif |
|
134 |
|
135 return NS_OK; |
|
136 } |
|
137 |
|
138 NS_IMETHODIMP |
|
139 nsStatusReporterManager::DumpReports() |
|
140 { |
|
141 static unsigned number = 1; |
|
142 nsresult rv; |
|
143 |
|
144 nsCString filename("status-reports-"); |
|
145 filename.AppendInt(getpid()); |
|
146 filename.AppendLiteral("-"); |
|
147 filename.AppendInt(number++); |
|
148 filename.AppendLiteral(".json"); |
|
149 |
|
150 // Open a file in NS_OS_TEMP_DIR for writing. |
|
151 // The file is initialized as "incomplete-status-reports-pid-number.json" in the |
|
152 // begining, it will be rename as "status-reports-pid-number.json" in the end. |
|
153 nsCOMPtr<nsIFile> tmpFile; |
|
154 rv = nsDumpUtils::OpenTempFile(NS_LITERAL_CSTRING("incomplete-") + |
|
155 filename, |
|
156 getter_AddRefs(tmpFile), |
|
157 NS_LITERAL_CSTRING("status-reports")); |
|
158 if (NS_WARN_IF(NS_FAILED(rv))) |
|
159 return rv; |
|
160 |
|
161 nsCOMPtr<nsIFileOutputStream> ostream = |
|
162 do_CreateInstance("@mozilla.org/network/file-output-stream;1"); |
|
163 rv = ostream->Init(tmpFile, -1, -1, 0); |
|
164 if (NS_WARN_IF(NS_FAILED(rv))) |
|
165 return rv; |
|
166 |
|
167 //Write the reports to the file |
|
168 |
|
169 DUMP(ostream, " [Sysdump Report Start]: "); |
|
170 |
|
171 nsCOMPtr<nsISimpleEnumerator> e; |
|
172 bool more; |
|
173 EnumerateReporters(getter_AddRefs(e)); |
|
174 while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) { |
|
175 nsCOMPtr<nsISupports> supports; |
|
176 e->GetNext(getter_AddRefs(supports)); |
|
177 nsCOMPtr<nsIStatusReporter> r = do_QueryInterface(supports); |
|
178 |
|
179 nsCString process; |
|
180 rv = r->GetProcess(process); |
|
181 if (NS_WARN_IF(NS_FAILED(rv))) |
|
182 return rv; |
|
183 |
|
184 nsCString name; |
|
185 rv = r->GetName(name); |
|
186 if (NS_WARN_IF(NS_FAILED(rv))) |
|
187 return rv; |
|
188 |
|
189 nsCString description; |
|
190 rv = r->GetDescription(description); |
|
191 if (NS_WARN_IF(NS_FAILED(rv))) |
|
192 return rv; |
|
193 |
|
194 rv = DumpReport(ostream, process, name, description); |
|
195 if (NS_WARN_IF(NS_FAILED(rv))) |
|
196 return rv; |
|
197 } |
|
198 |
|
199 DUMP(ostream, "\n [Sysdump Report End] "); |
|
200 |
|
201 rv = ostream->Close(); |
|
202 if (NS_WARN_IF(NS_FAILED(rv))) |
|
203 return rv; |
|
204 |
|
205 // Rename the status reports file |
|
206 nsCOMPtr<nsIFile> srFinalFile; |
|
207 rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(srFinalFile)); |
|
208 if (NS_WARN_IF(NS_FAILED(rv))) |
|
209 return rv; |
|
210 |
|
211 #ifdef ANDROID |
|
212 rv = srFinalFile->AppendNative(NS_LITERAL_CSTRING("status-reports")); |
|
213 if (NS_WARN_IF(NS_FAILED(rv))) |
|
214 return rv; |
|
215 #endif |
|
216 |
|
217 rv = srFinalFile->AppendNative(filename); |
|
218 if (NS_WARN_IF(NS_FAILED(rv))) |
|
219 return rv; |
|
220 |
|
221 rv = srFinalFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600); |
|
222 if (NS_WARN_IF(NS_FAILED(rv))) |
|
223 return rv; |
|
224 |
|
225 nsAutoString srActualFinalFilename; |
|
226 rv = srFinalFile->GetLeafName(srActualFinalFilename); |
|
227 if (NS_WARN_IF(NS_FAILED(rv))) |
|
228 return rv; |
|
229 |
|
230 rv = tmpFile->MoveTo(/* directory */ nullptr, srActualFinalFilename); |
|
231 |
|
232 if (NS_WARN_IF(NS_FAILED(rv))) |
|
233 return rv; |
|
234 |
|
235 return NS_OK; |
|
236 } |
|
237 |
|
238 NS_IMETHODIMP |
|
239 nsStatusReporterManager::EnumerateReporters(nsISimpleEnumerator** result) |
|
240 { |
|
241 return NS_NewArrayEnumerator(result, mReporters); |
|
242 } |
|
243 |
|
244 NS_IMETHODIMP |
|
245 nsStatusReporterManager::RegisterReporter(nsIStatusReporter* reporter) |
|
246 { |
|
247 if (mReporters.IndexOf(reporter) != -1) |
|
248 return NS_ERROR_FAILURE; |
|
249 |
|
250 mReporters.AppendObject(reporter); |
|
251 gNumReporters++; |
|
252 return NS_OK; |
|
253 } |
|
254 |
|
255 NS_IMETHODIMP |
|
256 nsStatusReporterManager::UnregisterReporter(nsIStatusReporter* reporter) |
|
257 { |
|
258 if (!mReporters.RemoveObject(reporter)) |
|
259 return NS_ERROR_FAILURE; |
|
260 gNumReporters--; |
|
261 return NS_OK; |
|
262 } |
|
263 |
|
264 nsresult |
|
265 NS_RegisterStatusReporter (nsIStatusReporter* reporter) |
|
266 { |
|
267 nsCOMPtr<nsIStatusReporterManager> mgr = |
|
268 do_GetService("@mozilla.org/status-reporter-manager;1"); |
|
269 if (mgr == nullptr) |
|
270 return NS_ERROR_FAILURE; |
|
271 return mgr->RegisterReporter(reporter); |
|
272 } |
|
273 |
|
274 nsresult |
|
275 NS_UnregisterStatusReporter (nsIStatusReporter* reporter) |
|
276 { |
|
277 nsCOMPtr<nsIStatusReporterManager> mgr = |
|
278 do_GetService("@mozilla.org/status-reporter-manager;1"); |
|
279 if (mgr == nullptr) |
|
280 return NS_ERROR_FAILURE; |
|
281 return mgr->UnregisterReporter(reporter); |
|
282 } |
|
283 |
|
284 nsresult |
|
285 NS_DumpStatusReporter () |
|
286 { |
|
287 nsCOMPtr<nsIStatusReporterManager> mgr = |
|
288 do_GetService("@mozilla.org/status-reporter-manager;1"); |
|
289 if (mgr == nullptr) |
|
290 return NS_ERROR_FAILURE; |
|
291 return mgr->DumpReports(); |
|
292 } |