summaryrefslogtreecommitdiffstats
path: root/xpcom/base/nsStatusReporterManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/base/nsStatusReporterManager.cpp')
-rw-r--r--xpcom/base/nsStatusReporterManager.cpp320
1 files changed, 320 insertions, 0 deletions
diff --git a/xpcom/base/nsStatusReporterManager.cpp b/xpcom/base/nsStatusReporterManager.cpp
new file mode 100644
index 000000000..491e7d458
--- /dev/null
+++ b/xpcom/base/nsStatusReporterManager.cpp
@@ -0,0 +1,320 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsStatusReporterManager.h"
+#include "nsCOMPtr.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsArrayEnumerator.h"
+#include "nsISimpleEnumerator.h"
+#include "nsIFile.h"
+#include "nsDumpUtils.h"
+#include "nsIFileStreams.h"
+#include "nsPrintfCString.h"
+
+#ifdef XP_WIN
+#include <process.h>
+#define getpid _getpid
+#else
+#include <unistd.h>
+#endif
+
+#ifdef XP_UNIX
+#define DO_STATUS_REPORT 1
+#endif
+
+#ifdef DO_STATUS_REPORT // {
+namespace {
+
+class DumpStatusInfoToTempDirRunnable : public mozilla::Runnable
+{
+public:
+ DumpStatusInfoToTempDirRunnable()
+ {
+ }
+
+ NS_IMETHOD Run() override
+ {
+ nsCOMPtr<nsIStatusReporterManager> mgr =
+ do_GetService("@mozilla.org/status-reporter-manager;1");
+ mgr->DumpReports();
+ return NS_OK;
+ }
+};
+
+void
+doStatusReport(const nsCString& aInputStr)
+{
+ LOG("FifoWatcher(%s) dispatching status report runnable.", aInputStr.get());
+ RefPtr<DumpStatusInfoToTempDirRunnable> runnable =
+ new DumpStatusInfoToTempDirRunnable();
+ NS_DispatchToMainThread(runnable);
+}
+
+} //anonymous namespace
+#endif // DO_STATUS_REPORT }
+
+static bool gStatusReportProgress = 0;
+static int gNumReporters = 0;
+
+nsresult
+getStatus(nsACString& aDesc)
+{
+ if (!gStatusReportProgress) {
+ aDesc.AssignLiteral("Init");
+ } else {
+ aDesc.AssignLiteral("Running: There are ");
+ aDesc.AppendInt(gNumReporters);
+ aDesc.AppendLiteral(" reporters");
+ }
+ return NS_OK;
+}
+
+NS_STATUS_REPORTER_IMPLEMENT(StatusReporter, "StatusReporter State", getStatus)
+
+#define DUMP(o, s) \
+ do { \
+ const char* s2 = (s); \
+ uint32_t dummy; \
+ nsresult rvDump = (o)->Write((s2), strlen(s2), &dummy); \
+ if (NS_WARN_IF(NS_FAILED(rvDump))) \
+ return rvDump; \
+ } while (0)
+
+static nsresult
+DumpReport(nsIFileOutputStream* aOStream, const nsCString& aProcess,
+ const nsCString& aName, const nsCString& aDescription)
+{
+ if (aProcess.IsEmpty()) {
+ int pid = getpid();
+ nsPrintfCString pidStr("PID %u", pid);
+ DUMP(aOStream, "\n {\n \"Process\": \"");
+ DUMP(aOStream, pidStr.get());
+ } else {
+ DUMP(aOStream, "\n { \"Unknown Process\": \"");
+ }
+
+ DUMP(aOStream, "\",\n \"Reporter name\": \"");
+ DUMP(aOStream, aName.get());
+
+ DUMP(aOStream, "\",\n \"Status Description\": [\"");
+ nsCString desc = aDescription;
+ desc.ReplaceSubstring("|", "\",\"");
+ DUMP(aOStream, desc.get());
+
+ DUMP(aOStream, "\"]\n }");
+
+ return NS_OK;
+}
+
+/**
+ ** nsStatusReporterManager implementation
+ **/
+
+NS_IMPL_ISUPPORTS(nsStatusReporterManager, nsIStatusReporterManager)
+
+nsStatusReporterManager::nsStatusReporterManager()
+{
+}
+
+nsStatusReporterManager::~nsStatusReporterManager()
+{
+}
+
+NS_IMETHODIMP
+nsStatusReporterManager::Init()
+{
+ RegisterReporter(new NS_STATUS_REPORTER_NAME(StatusReporter));
+ gStatusReportProgress = 1;
+
+#ifdef DO_STATUS_REPORT
+ if (FifoWatcher::MaybeCreate()) {
+ FifoWatcher* fw = FifoWatcher::GetSingleton();
+ fw->RegisterCallback(NS_LITERAL_CSTRING("status report"), doStatusReport);
+ }
+#endif
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStatusReporterManager::DumpReports()
+{
+ static unsigned number = 1;
+ nsresult rv;
+
+ nsCString filename("status-reports-");
+ filename.AppendInt(getpid());
+ filename.Append('-');
+ filename.AppendInt(number++);
+ filename.AppendLiteral(".json");
+
+ // Open a file in NS_OS_TEMP_DIR for writing.
+ // The file is initialized as "incomplete-status-reports-pid-number.json" in the
+ // begining, it will be rename as "status-reports-pid-number.json" in the end.
+ nsCOMPtr<nsIFile> tmpFile;
+ rv = nsDumpUtils::OpenTempFile(NS_LITERAL_CSTRING("incomplete-") +
+ filename,
+ getter_AddRefs(tmpFile),
+ NS_LITERAL_CSTRING("status-reports"));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ nsCOMPtr<nsIFileOutputStream> ostream =
+ do_CreateInstance("@mozilla.org/network/file-output-stream;1");
+ rv = ostream->Init(tmpFile, -1, -1, 0);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ //Write the reports to the file
+
+ DUMP(ostream, "{\n\"subject\":\"about:service reports\",\n");
+ DUMP(ostream, "\"reporters\": [ ");
+
+ nsCOMPtr<nsISimpleEnumerator> e;
+ bool more, first = true;
+ EnumerateReporters(getter_AddRefs(e));
+ while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
+ nsCOMPtr<nsISupports> supports;
+ e->GetNext(getter_AddRefs(supports));
+ nsCOMPtr<nsIStatusReporter> r = do_QueryInterface(supports);
+
+ nsCString process;
+ rv = r->GetProcess(process);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ nsCString name;
+ rv = r->GetName(name);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ nsCString description;
+ rv = r->GetDescription(description);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ if (first) {
+ first = false;
+ } else {
+ DUMP(ostream, ",");
+ }
+
+ rv = DumpReport(ostream, process, name, description);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ }
+ DUMP(ostream, "\n]\n}\n");
+
+ rv = ostream->Close();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ // Rename the status reports file
+ nsCOMPtr<nsIFile> srFinalFile;
+ rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(srFinalFile));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+#ifdef ANDROID
+ rv = srFinalFile->AppendNative(NS_LITERAL_CSTRING("status-reports"));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+#endif
+
+ rv = srFinalFile->AppendNative(filename);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ rv = srFinalFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ nsAutoString srActualFinalFilename;
+ rv = srFinalFile->GetLeafName(srActualFinalFilename);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ rv = tmpFile->MoveTo(/* directory */ nullptr, srActualFinalFilename);
+
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStatusReporterManager::EnumerateReporters(nsISimpleEnumerator** aResult)
+{
+ return NS_NewArrayEnumerator(aResult, mReporters);
+}
+
+NS_IMETHODIMP
+nsStatusReporterManager::RegisterReporter(nsIStatusReporter* aReporter)
+{
+ if (mReporters.IndexOf(aReporter) != -1) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mReporters.AppendObject(aReporter);
+ gNumReporters++;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStatusReporterManager::UnregisterReporter(nsIStatusReporter* aReporter)
+{
+ if (!mReporters.RemoveObject(aReporter)) {
+ return NS_ERROR_FAILURE;
+ }
+ gNumReporters--;
+ return NS_OK;
+}
+
+nsresult
+NS_RegisterStatusReporter(nsIStatusReporter* aReporter)
+{
+ nsCOMPtr<nsIStatusReporterManager> mgr =
+ do_GetService("@mozilla.org/status-reporter-manager;1");
+ if (!mgr) {
+ return NS_ERROR_FAILURE;
+ }
+ return mgr->RegisterReporter(aReporter);
+}
+
+nsresult
+NS_UnregisterStatusReporter(nsIStatusReporter* aReporter)
+{
+ nsCOMPtr<nsIStatusReporterManager> mgr =
+ do_GetService("@mozilla.org/status-reporter-manager;1");
+ if (!mgr) {
+ return NS_ERROR_FAILURE;
+ }
+ return mgr->UnregisterReporter(aReporter);
+}
+
+nsresult
+NS_DumpStatusReporter()
+{
+ nsCOMPtr<nsIStatusReporterManager> mgr =
+ do_GetService("@mozilla.org/status-reporter-manager;1");
+ if (!mgr) {
+ return NS_ERROR_FAILURE;
+ }
+ return mgr->DumpReports();
+}