Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
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"
17 #ifdef XP_WIN
18 #include <process.h>
19 #define getpid _getpid
20 #else
21 #include <unistd.h>
22 #endif
24 #ifdef XP_UNIX
25 #define DO_STATUS_REPORT 1
26 #endif
28 #ifdef DO_STATUS_REPORT // {
29 namespace {
31 class DumpStatusInfoToTempDirRunnable : public nsRunnable
32 {
33 public:
34 DumpStatusInfoToTempDirRunnable()
35 {}
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 };
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 }
54 } //anonymous namespace
55 #endif // DO_STATUS_REPORT }
57 static bool gStatusReportProgress = 0;
58 static int gNumReporters = 0;
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 }
72 NS_STATUS_REPORTER_IMPLEMENT(StatusReporter, "StatusReporter State", getStatus)
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)
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 }
98 DUMP(aOStream, "\", \"Reporter name\": \"");
99 DUMP(aOStream, aName.get());
101 DUMP(aOStream, "\", \"Status Description\": \"");
102 DUMP(aOStream, aDescription.get());
103 DUMP(aOStream, "\"}");
105 return NS_OK;
106 }
108 /**
109 ** nsStatusReporterManager implementation
110 **/
112 NS_IMPL_ISUPPORTS(nsStatusReporterManager, nsIStatusReporterManager)
114 nsStatusReporterManager::nsStatusReporterManager()
115 {
116 }
118 nsStatusReporterManager::~nsStatusReporterManager()
119 {
120 }
122 NS_IMETHODIMP
123 nsStatusReporterManager::Init()
124 {
125 RegisterReporter(new NS_STATUS_REPORTER_NAME(StatusReporter));
126 gStatusReportProgress = 1;
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
135 return NS_OK;
136 }
138 NS_IMETHODIMP
139 nsStatusReporterManager::DumpReports()
140 {
141 static unsigned number = 1;
142 nsresult rv;
144 nsCString filename("status-reports-");
145 filename.AppendInt(getpid());
146 filename.AppendLiteral("-");
147 filename.AppendInt(number++);
148 filename.AppendLiteral(".json");
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;
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;
167 //Write the reports to the file
169 DUMP(ostream, " [Sysdump Report Start]: ");
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);
179 nsCString process;
180 rv = r->GetProcess(process);
181 if (NS_WARN_IF(NS_FAILED(rv)))
182 return rv;
184 nsCString name;
185 rv = r->GetName(name);
186 if (NS_WARN_IF(NS_FAILED(rv)))
187 return rv;
189 nsCString description;
190 rv = r->GetDescription(description);
191 if (NS_WARN_IF(NS_FAILED(rv)))
192 return rv;
194 rv = DumpReport(ostream, process, name, description);
195 if (NS_WARN_IF(NS_FAILED(rv)))
196 return rv;
197 }
199 DUMP(ostream, "\n [Sysdump Report End] ");
201 rv = ostream->Close();
202 if (NS_WARN_IF(NS_FAILED(rv)))
203 return rv;
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;
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
217 rv = srFinalFile->AppendNative(filename);
218 if (NS_WARN_IF(NS_FAILED(rv)))
219 return rv;
221 rv = srFinalFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
222 if (NS_WARN_IF(NS_FAILED(rv)))
223 return rv;
225 nsAutoString srActualFinalFilename;
226 rv = srFinalFile->GetLeafName(srActualFinalFilename);
227 if (NS_WARN_IF(NS_FAILED(rv)))
228 return rv;
230 rv = tmpFile->MoveTo(/* directory */ nullptr, srActualFinalFilename);
232 if (NS_WARN_IF(NS_FAILED(rv)))
233 return rv;
235 return NS_OK;
236 }
238 NS_IMETHODIMP
239 nsStatusReporterManager::EnumerateReporters(nsISimpleEnumerator** result)
240 {
241 return NS_NewArrayEnumerator(result, mReporters);
242 }
244 NS_IMETHODIMP
245 nsStatusReporterManager::RegisterReporter(nsIStatusReporter* reporter)
246 {
247 if (mReporters.IndexOf(reporter) != -1)
248 return NS_ERROR_FAILURE;
250 mReporters.AppendObject(reporter);
251 gNumReporters++;
252 return NS_OK;
253 }
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 }
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 }
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 }
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 }