Line data Source code
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 0 : class DumpStatusInfoToTempDirRunnable : public mozilla::Runnable
32 : {
33 : public:
34 0 : DumpStatusInfoToTempDirRunnable()
35 0 : : mozilla::Runnable("DumpStatusInfoToTempDirRunnable")
36 : {
37 0 : }
38 :
39 0 : NS_IMETHOD Run() override
40 : {
41 : nsCOMPtr<nsIStatusReporterManager> mgr =
42 0 : do_GetService("@mozilla.org/status-reporter-manager;1");
43 0 : mgr->DumpReports();
44 0 : return NS_OK;
45 : }
46 : };
47 :
48 : void
49 0 : doStatusReport(const nsCString& aInputStr)
50 : {
51 : LOG("FifoWatcher(%s) dispatching status report runnable.", aInputStr.get());
52 : RefPtr<DumpStatusInfoToTempDirRunnable> runnable =
53 0 : new DumpStatusInfoToTempDirRunnable();
54 0 : NS_DispatchToMainThread(runnable);
55 0 : }
56 :
57 : } //anonymous namespace
58 : #endif // DO_STATUS_REPORT }
59 :
60 : static bool gStatusReportProgress = 0;
61 : static int gNumReporters = 0;
62 :
63 : nsresult
64 0 : getStatus(nsACString& aDesc)
65 : {
66 0 : if (!gStatusReportProgress) {
67 0 : aDesc.AssignLiteral("Init");
68 : } else {
69 0 : aDesc.AssignLiteral("Running: There are ");
70 0 : aDesc.AppendInt(gNumReporters);
71 0 : aDesc.AppendLiteral(" reporters");
72 : }
73 0 : return NS_OK;
74 : }
75 :
76 0 : NS_STATUS_REPORTER_IMPLEMENT(StatusReporter, "StatusReporter State", getStatus)
77 :
78 : #define DUMP(o, s) \
79 : do { \
80 : const char* s2 = (s); \
81 : uint32_t dummy; \
82 : nsresult rvDump = (o)->Write((s2), strlen(s2), &dummy); \
83 : if (NS_WARN_IF(NS_FAILED(rvDump))) \
84 : return rvDump; \
85 : } while (0)
86 :
87 : static nsresult
88 0 : DumpReport(nsIFileOutputStream* aOStream, const nsCString& aProcess,
89 : const nsCString& aName, const nsCString& aDescription)
90 : {
91 0 : if (aProcess.IsEmpty()) {
92 0 : int pid = getpid();
93 0 : nsPrintfCString pidStr("PID %u", pid);
94 0 : DUMP(aOStream, "\n {\n \"Process\": \"");
95 0 : DUMP(aOStream, pidStr.get());
96 : } else {
97 0 : DUMP(aOStream, "\n { \"Unknown Process\": \"");
98 : }
99 :
100 0 : DUMP(aOStream, "\",\n \"Reporter name\": \"");
101 0 : DUMP(aOStream, aName.get());
102 :
103 0 : DUMP(aOStream, "\",\n \"Status Description\": [\"");
104 0 : nsCString desc = aDescription;
105 0 : desc.ReplaceSubstring("|", "\",\"");
106 0 : DUMP(aOStream, desc.get());
107 :
108 0 : DUMP(aOStream, "\"]\n }");
109 :
110 0 : return NS_OK;
111 : }
112 :
113 : /**
114 : ** nsStatusReporterManager implementation
115 : **/
116 :
117 0 : NS_IMPL_ISUPPORTS(nsStatusReporterManager, nsIStatusReporterManager)
118 :
119 0 : nsStatusReporterManager::nsStatusReporterManager()
120 : {
121 0 : }
122 :
123 0 : nsStatusReporterManager::~nsStatusReporterManager()
124 : {
125 0 : }
126 :
127 : NS_IMETHODIMP
128 0 : nsStatusReporterManager::Init()
129 : {
130 0 : RegisterReporter(new NS_STATUS_REPORTER_NAME(StatusReporter));
131 0 : gStatusReportProgress = 1;
132 :
133 : #ifdef DO_STATUS_REPORT
134 0 : if (FifoWatcher::MaybeCreate()) {
135 0 : FifoWatcher* fw = FifoWatcher::GetSingleton();
136 0 : fw->RegisterCallback(NS_LITERAL_CSTRING("status report"), doStatusReport);
137 : }
138 : #endif
139 :
140 0 : return NS_OK;
141 : }
142 :
143 : NS_IMETHODIMP
144 0 : nsStatusReporterManager::DumpReports()
145 : {
146 : static unsigned number = 1;
147 : nsresult rv;
148 :
149 0 : nsCString filename("status-reports-");
150 0 : filename.AppendInt((uint32_t)getpid());
151 0 : filename.Append('-');
152 0 : filename.AppendInt(number++);
153 0 : filename.AppendLiteral(".json");
154 :
155 : // Open a file in NS_OS_TEMP_DIR for writing.
156 : // The file is initialized as "incomplete-status-reports-pid-number.json" in the
157 : // begining, it will be rename as "status-reports-pid-number.json" in the end.
158 0 : nsCOMPtr<nsIFile> tmpFile;
159 0 : rv = nsDumpUtils::OpenTempFile(NS_LITERAL_CSTRING("incomplete-") +
160 0 : filename,
161 0 : getter_AddRefs(tmpFile),
162 0 : NS_LITERAL_CSTRING("status-reports"));
163 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
164 0 : return rv;
165 : }
166 :
167 : nsCOMPtr<nsIFileOutputStream> ostream =
168 0 : do_CreateInstance("@mozilla.org/network/file-output-stream;1");
169 0 : rv = ostream->Init(tmpFile, -1, -1, 0);
170 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
171 0 : return rv;
172 : }
173 :
174 : //Write the reports to the file
175 :
176 0 : DUMP(ostream, "{\n\"subject\":\"about:service reports\",\n");
177 0 : DUMP(ostream, "\"reporters\": [ ");
178 :
179 0 : nsCOMPtr<nsISimpleEnumerator> e;
180 0 : bool more, first = true;
181 0 : EnumerateReporters(getter_AddRefs(e));
182 0 : while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
183 0 : nsCOMPtr<nsISupports> supports;
184 0 : e->GetNext(getter_AddRefs(supports));
185 0 : nsCOMPtr<nsIStatusReporter> r = do_QueryInterface(supports);
186 :
187 0 : nsCString process;
188 0 : rv = r->GetProcess(process);
189 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
190 0 : return rv;
191 : }
192 :
193 0 : nsCString name;
194 0 : rv = r->GetName(name);
195 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
196 0 : return rv;
197 : }
198 :
199 0 : nsCString description;
200 0 : rv = r->GetDescription(description);
201 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
202 0 : return rv;
203 : }
204 :
205 0 : if (first) {
206 0 : first = false;
207 : } else {
208 0 : DUMP(ostream, ",");
209 : }
210 :
211 0 : rv = DumpReport(ostream, process, name, description);
212 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
213 0 : return rv;
214 : }
215 : }
216 0 : DUMP(ostream, "\n]\n}\n");
217 :
218 0 : rv = ostream->Close();
219 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
220 0 : return rv;
221 : }
222 :
223 : // Rename the status reports file
224 0 : nsCOMPtr<nsIFile> srFinalFile;
225 0 : rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(srFinalFile));
226 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
227 0 : return rv;
228 : }
229 :
230 : #ifdef ANDROID
231 : rv = srFinalFile->AppendNative(NS_LITERAL_CSTRING("status-reports"));
232 : if (NS_WARN_IF(NS_FAILED(rv))) {
233 : return rv;
234 : }
235 : #endif
236 :
237 0 : rv = srFinalFile->AppendNative(filename);
238 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
239 0 : return rv;
240 : }
241 :
242 0 : rv = srFinalFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
243 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
244 0 : return rv;
245 : }
246 :
247 0 : nsAutoString srActualFinalFilename;
248 0 : rv = srFinalFile->GetLeafName(srActualFinalFilename);
249 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
250 0 : return rv;
251 : }
252 :
253 0 : rv = tmpFile->MoveTo(/* directory */ nullptr, srActualFinalFilename);
254 :
255 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
256 0 : return rv;
257 : }
258 :
259 0 : return NS_OK;
260 : }
261 :
262 : NS_IMETHODIMP
263 0 : nsStatusReporterManager::EnumerateReporters(nsISimpleEnumerator** aResult)
264 : {
265 0 : return NS_NewArrayEnumerator(aResult, mReporters);
266 : }
267 :
268 : NS_IMETHODIMP
269 0 : nsStatusReporterManager::RegisterReporter(nsIStatusReporter* aReporter)
270 : {
271 0 : if (mReporters.IndexOf(aReporter) != -1) {
272 0 : return NS_ERROR_FAILURE;
273 : }
274 :
275 0 : mReporters.AppendObject(aReporter);
276 0 : gNumReporters++;
277 0 : return NS_OK;
278 : }
279 :
280 : NS_IMETHODIMP
281 0 : nsStatusReporterManager::UnregisterReporter(nsIStatusReporter* aReporter)
282 : {
283 0 : if (!mReporters.RemoveObject(aReporter)) {
284 0 : return NS_ERROR_FAILURE;
285 : }
286 0 : gNumReporters--;
287 0 : return NS_OK;
288 : }
289 :
290 : nsresult
291 0 : NS_RegisterStatusReporter(nsIStatusReporter* aReporter)
292 : {
293 : nsCOMPtr<nsIStatusReporterManager> mgr =
294 0 : do_GetService("@mozilla.org/status-reporter-manager;1");
295 0 : if (!mgr) {
296 0 : return NS_ERROR_FAILURE;
297 : }
298 0 : return mgr->RegisterReporter(aReporter);
299 : }
300 :
301 : nsresult
302 0 : NS_UnregisterStatusReporter(nsIStatusReporter* aReporter)
303 : {
304 : nsCOMPtr<nsIStatusReporterManager> mgr =
305 0 : do_GetService("@mozilla.org/status-reporter-manager;1");
306 0 : if (!mgr) {
307 0 : return NS_ERROR_FAILURE;
308 : }
309 0 : return mgr->UnregisterReporter(aReporter);
310 : }
311 :
312 : nsresult
313 0 : NS_DumpStatusReporter()
314 : {
315 : nsCOMPtr<nsIStatusReporterManager> mgr =
316 0 : do_GetService("@mozilla.org/status-reporter-manager;1");
317 0 : if (!mgr) {
318 0 : return NS_ERROR_FAILURE;
319 : }
320 0 : return mgr->DumpReports();
321 : }
|