diff -r 000000000000 -r 6474c204b198 xpcom/base/nsStatusReporterManager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xpcom/base/nsStatusReporterManager.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,292 @@ +/* -*- 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 +#define getpid _getpid +#else +#include +#endif + +#ifdef XP_UNIX +#define DO_STATUS_REPORT 1 +#endif + +#ifdef DO_STATUS_REPORT // { +namespace { + +class DumpStatusInfoToTempDirRunnable : public nsRunnable +{ +public: + DumpStatusInfoToTempDirRunnable() + {} + + NS_IMETHOD Run() + { + nsCOMPtr mgr = + do_GetService("@mozilla.org/status-reporter-manager;1"); + mgr->DumpReports(); + return NS_OK; + } +}; + +void doStatusReport(const nsCString& inputStr) +{ + LOG("FifoWatcher(%s) dispatching status report runnable.", inputStr.get()); + nsRefPtr runnable = + new DumpStatusInfoToTempDirRunnable(); + NS_DispatchToMainThread(runnable); +} + +} //anonymous namespace +#endif // DO_STATUS_REPORT } + +static bool gStatusReportProgress = 0; +static int gNumReporters = 0; + +nsresult getStatus(nsACString& desc) +{ + if(!gStatusReportProgress) + desc.AssignLiteral("Init"); + else { + desc.AssignLiteral("Running:\nThere are "); + desc.AppendInt(gNumReporters); + desc.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 rv = (o)->Write((s2), strlen(s2), &dummy); \ + if (NS_WARN_IF(NS_FAILED(rv))) \ + return rv; \ + } while (0) + +static nsresult +DumpReport(nsIFileOutputStream* aOStream, const nsCString& aProcess, + const nsCString& aName, const nsCString& aDescription) +{ + int pid; + if (aProcess.IsEmpty()) { + pid = getpid(); + nsPrintfCString pidStr("PID %u", pid); + DUMP(aOStream, "\n {\"Process\": \""); + DUMP(aOStream, pidStr.get()); + } else { + pid = 0; + DUMP(aOStream, "\n {\"Unknown Process\": \""); + } + + DUMP(aOStream, "\", \"Reporter name\": \""); + DUMP(aOStream, aName.get()); + + DUMP(aOStream, "\", \"Status Description\": \""); + DUMP(aOStream, aDescription.get()); + DUMP(aOStream, "\"}"); + + 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.AppendLiteral("-"); + 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 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 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, " [Sysdump Report Start]: "); + + nsCOMPtr e; + bool more; + EnumerateReporters(getter_AddRefs(e)); + while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) { + nsCOMPtr supports; + e->GetNext(getter_AddRefs(supports)); + nsCOMPtr 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; + + rv = DumpReport(ostream, process, name, description); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + } + + DUMP(ostream, "\n [Sysdump Report End] "); + + rv = ostream->Close(); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + // Rename the status reports file + nsCOMPtr 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** result) +{ + return NS_NewArrayEnumerator(result, mReporters); +} + +NS_IMETHODIMP +nsStatusReporterManager::RegisterReporter(nsIStatusReporter* reporter) +{ + if (mReporters.IndexOf(reporter) != -1) + return NS_ERROR_FAILURE; + + mReporters.AppendObject(reporter); + gNumReporters++; + return NS_OK; +} + +NS_IMETHODIMP +nsStatusReporterManager::UnregisterReporter(nsIStatusReporter* reporter) +{ + if (!mReporters.RemoveObject(reporter)) + return NS_ERROR_FAILURE; + gNumReporters--; + return NS_OK; +} + +nsresult +NS_RegisterStatusReporter (nsIStatusReporter* reporter) +{ + nsCOMPtr mgr = + do_GetService("@mozilla.org/status-reporter-manager;1"); + if (mgr == nullptr) + return NS_ERROR_FAILURE; + return mgr->RegisterReporter(reporter); +} + +nsresult +NS_UnregisterStatusReporter (nsIStatusReporter* reporter) +{ + nsCOMPtr mgr = + do_GetService("@mozilla.org/status-reporter-manager;1"); + if (mgr == nullptr) + return NS_ERROR_FAILURE; + return mgr->UnregisterReporter(reporter); +} + +nsresult +NS_DumpStatusReporter () +{ + nsCOMPtr mgr = + do_GetService("@mozilla.org/status-reporter-manager;1"); + if (mgr == nullptr) + return NS_ERROR_FAILURE; + return mgr->DumpReports(); +}