1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/base/nsStatusReporterManager.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,292 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsStatusReporterManager.h" 1.11 +#include "nsCOMPtr.h" 1.12 +#include "nsDirectoryServiceDefs.h" 1.13 +#include "nsArrayEnumerator.h" 1.14 +#include "nsISimpleEnumerator.h" 1.15 +#include "nsIFile.h" 1.16 +#include "nsDumpUtils.h" 1.17 +#include "nsIFileStreams.h" 1.18 +#include "nsPrintfCString.h" 1.19 + 1.20 +#ifdef XP_WIN 1.21 +#include <process.h> 1.22 +#define getpid _getpid 1.23 +#else 1.24 +#include <unistd.h> 1.25 +#endif 1.26 + 1.27 +#ifdef XP_UNIX 1.28 +#define DO_STATUS_REPORT 1 1.29 +#endif 1.30 + 1.31 +#ifdef DO_STATUS_REPORT // { 1.32 +namespace { 1.33 + 1.34 +class DumpStatusInfoToTempDirRunnable : public nsRunnable 1.35 +{ 1.36 +public: 1.37 + DumpStatusInfoToTempDirRunnable() 1.38 + {} 1.39 + 1.40 + NS_IMETHOD Run() 1.41 + { 1.42 + nsCOMPtr<nsIStatusReporterManager> mgr = 1.43 + do_GetService("@mozilla.org/status-reporter-manager;1"); 1.44 + mgr->DumpReports(); 1.45 + return NS_OK; 1.46 + } 1.47 +}; 1.48 + 1.49 +void doStatusReport(const nsCString& inputStr) 1.50 +{ 1.51 + LOG("FifoWatcher(%s) dispatching status report runnable.", inputStr.get()); 1.52 + nsRefPtr<DumpStatusInfoToTempDirRunnable> runnable = 1.53 + new DumpStatusInfoToTempDirRunnable(); 1.54 + NS_DispatchToMainThread(runnable); 1.55 +} 1.56 + 1.57 +} //anonymous namespace 1.58 +#endif // DO_STATUS_REPORT } 1.59 + 1.60 +static bool gStatusReportProgress = 0; 1.61 +static int gNumReporters = 0; 1.62 + 1.63 +nsresult getStatus(nsACString& desc) 1.64 +{ 1.65 + if(!gStatusReportProgress) 1.66 + desc.AssignLiteral("Init"); 1.67 + else { 1.68 + desc.AssignLiteral("Running:\nThere are "); 1.69 + desc.AppendInt(gNumReporters); 1.70 + desc.AppendLiteral(" reporters"); 1.71 + } 1.72 + return NS_OK; 1.73 +} 1.74 + 1.75 +NS_STATUS_REPORTER_IMPLEMENT(StatusReporter, "StatusReporter State", getStatus) 1.76 + 1.77 +#define DUMP(o, s) \ 1.78 + do { \ 1.79 + const char* s2 = (s); \ 1.80 + uint32_t dummy; \ 1.81 + nsresult rv = (o)->Write((s2), strlen(s2), &dummy); \ 1.82 + if (NS_WARN_IF(NS_FAILED(rv))) \ 1.83 + return rv; \ 1.84 + } while (0) 1.85 + 1.86 +static nsresult 1.87 +DumpReport(nsIFileOutputStream* aOStream, const nsCString& aProcess, 1.88 + const nsCString& aName, const nsCString& aDescription) 1.89 +{ 1.90 + int pid; 1.91 + if (aProcess.IsEmpty()) { 1.92 + pid = getpid(); 1.93 + nsPrintfCString pidStr("PID %u", pid); 1.94 + DUMP(aOStream, "\n {\"Process\": \""); 1.95 + DUMP(aOStream, pidStr.get()); 1.96 + } else { 1.97 + pid = 0; 1.98 + DUMP(aOStream, "\n {\"Unknown Process\": \""); 1.99 + } 1.100 + 1.101 + DUMP(aOStream, "\", \"Reporter name\": \""); 1.102 + DUMP(aOStream, aName.get()); 1.103 + 1.104 + DUMP(aOStream, "\", \"Status Description\": \""); 1.105 + DUMP(aOStream, aDescription.get()); 1.106 + DUMP(aOStream, "\"}"); 1.107 + 1.108 + return NS_OK; 1.109 +} 1.110 + 1.111 +/** 1.112 + ** nsStatusReporterManager implementation 1.113 + **/ 1.114 + 1.115 +NS_IMPL_ISUPPORTS(nsStatusReporterManager, nsIStatusReporterManager) 1.116 + 1.117 +nsStatusReporterManager::nsStatusReporterManager() 1.118 +{ 1.119 +} 1.120 + 1.121 +nsStatusReporterManager::~nsStatusReporterManager() 1.122 +{ 1.123 +} 1.124 + 1.125 +NS_IMETHODIMP 1.126 +nsStatusReporterManager::Init() 1.127 +{ 1.128 + RegisterReporter(new NS_STATUS_REPORTER_NAME(StatusReporter)); 1.129 + gStatusReportProgress = 1; 1.130 + 1.131 +#ifdef DO_STATUS_REPORT 1.132 + if (FifoWatcher::MaybeCreate()) { 1.133 + FifoWatcher* fw = FifoWatcher::GetSingleton(); 1.134 + fw->RegisterCallback(NS_LITERAL_CSTRING("status report"),doStatusReport); 1.135 + } 1.136 +#endif 1.137 + 1.138 + return NS_OK; 1.139 +} 1.140 + 1.141 +NS_IMETHODIMP 1.142 +nsStatusReporterManager::DumpReports() 1.143 +{ 1.144 + static unsigned number = 1; 1.145 + nsresult rv; 1.146 + 1.147 + nsCString filename("status-reports-"); 1.148 + filename.AppendInt(getpid()); 1.149 + filename.AppendLiteral("-"); 1.150 + filename.AppendInt(number++); 1.151 + filename.AppendLiteral(".json"); 1.152 + 1.153 + // Open a file in NS_OS_TEMP_DIR for writing. 1.154 + // The file is initialized as "incomplete-status-reports-pid-number.json" in the 1.155 + // begining, it will be rename as "status-reports-pid-number.json" in the end. 1.156 + nsCOMPtr<nsIFile> tmpFile; 1.157 + rv = nsDumpUtils::OpenTempFile(NS_LITERAL_CSTRING("incomplete-") + 1.158 + filename, 1.159 + getter_AddRefs(tmpFile), 1.160 + NS_LITERAL_CSTRING("status-reports")); 1.161 + if (NS_WARN_IF(NS_FAILED(rv))) 1.162 + return rv; 1.163 + 1.164 + nsCOMPtr<nsIFileOutputStream> ostream = 1.165 + do_CreateInstance("@mozilla.org/network/file-output-stream;1"); 1.166 + rv = ostream->Init(tmpFile, -1, -1, 0); 1.167 + if (NS_WARN_IF(NS_FAILED(rv))) 1.168 + return rv; 1.169 + 1.170 + //Write the reports to the file 1.171 + 1.172 + DUMP(ostream, " [Sysdump Report Start]: "); 1.173 + 1.174 + nsCOMPtr<nsISimpleEnumerator> e; 1.175 + bool more; 1.176 + EnumerateReporters(getter_AddRefs(e)); 1.177 + while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) { 1.178 + nsCOMPtr<nsISupports> supports; 1.179 + e->GetNext(getter_AddRefs(supports)); 1.180 + nsCOMPtr<nsIStatusReporter> r = do_QueryInterface(supports); 1.181 + 1.182 + nsCString process; 1.183 + rv = r->GetProcess(process); 1.184 + if (NS_WARN_IF(NS_FAILED(rv))) 1.185 + return rv; 1.186 + 1.187 + nsCString name; 1.188 + rv = r->GetName(name); 1.189 + if (NS_WARN_IF(NS_FAILED(rv))) 1.190 + return rv; 1.191 + 1.192 + nsCString description; 1.193 + rv = r->GetDescription(description); 1.194 + if (NS_WARN_IF(NS_FAILED(rv))) 1.195 + return rv; 1.196 + 1.197 + rv = DumpReport(ostream, process, name, description); 1.198 + if (NS_WARN_IF(NS_FAILED(rv))) 1.199 + return rv; 1.200 + } 1.201 + 1.202 + DUMP(ostream, "\n [Sysdump Report End] "); 1.203 + 1.204 + rv = ostream->Close(); 1.205 + if (NS_WARN_IF(NS_FAILED(rv))) 1.206 + return rv; 1.207 + 1.208 + // Rename the status reports file 1.209 + nsCOMPtr<nsIFile> srFinalFile; 1.210 + rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(srFinalFile)); 1.211 + if (NS_WARN_IF(NS_FAILED(rv))) 1.212 + return rv; 1.213 + 1.214 +#ifdef ANDROID 1.215 + rv = srFinalFile->AppendNative(NS_LITERAL_CSTRING("status-reports")); 1.216 + if (NS_WARN_IF(NS_FAILED(rv))) 1.217 + return rv; 1.218 +#endif 1.219 + 1.220 + rv = srFinalFile->AppendNative(filename); 1.221 + if (NS_WARN_IF(NS_FAILED(rv))) 1.222 + return rv; 1.223 + 1.224 + rv = srFinalFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600); 1.225 + if (NS_WARN_IF(NS_FAILED(rv))) 1.226 + return rv; 1.227 + 1.228 + nsAutoString srActualFinalFilename; 1.229 + rv = srFinalFile->GetLeafName(srActualFinalFilename); 1.230 + if (NS_WARN_IF(NS_FAILED(rv))) 1.231 + return rv; 1.232 + 1.233 + rv = tmpFile->MoveTo(/* directory */ nullptr, srActualFinalFilename); 1.234 + 1.235 + if (NS_WARN_IF(NS_FAILED(rv))) 1.236 + return rv; 1.237 + 1.238 + return NS_OK; 1.239 +} 1.240 + 1.241 +NS_IMETHODIMP 1.242 +nsStatusReporterManager::EnumerateReporters(nsISimpleEnumerator** result) 1.243 +{ 1.244 + return NS_NewArrayEnumerator(result, mReporters); 1.245 +} 1.246 + 1.247 +NS_IMETHODIMP 1.248 +nsStatusReporterManager::RegisterReporter(nsIStatusReporter* reporter) 1.249 +{ 1.250 + if (mReporters.IndexOf(reporter) != -1) 1.251 + return NS_ERROR_FAILURE; 1.252 + 1.253 + mReporters.AppendObject(reporter); 1.254 + gNumReporters++; 1.255 + return NS_OK; 1.256 +} 1.257 + 1.258 +NS_IMETHODIMP 1.259 +nsStatusReporterManager::UnregisterReporter(nsIStatusReporter* reporter) 1.260 +{ 1.261 + if (!mReporters.RemoveObject(reporter)) 1.262 + return NS_ERROR_FAILURE; 1.263 + gNumReporters--; 1.264 + return NS_OK; 1.265 +} 1.266 + 1.267 +nsresult 1.268 +NS_RegisterStatusReporter (nsIStatusReporter* reporter) 1.269 +{ 1.270 + nsCOMPtr<nsIStatusReporterManager> mgr = 1.271 + do_GetService("@mozilla.org/status-reporter-manager;1"); 1.272 + if (mgr == nullptr) 1.273 + return NS_ERROR_FAILURE; 1.274 + return mgr->RegisterReporter(reporter); 1.275 +} 1.276 + 1.277 +nsresult 1.278 +NS_UnregisterStatusReporter (nsIStatusReporter* reporter) 1.279 +{ 1.280 + nsCOMPtr<nsIStatusReporterManager> mgr = 1.281 + do_GetService("@mozilla.org/status-reporter-manager;1"); 1.282 + if (mgr == nullptr) 1.283 + return NS_ERROR_FAILURE; 1.284 + return mgr->UnregisterReporter(reporter); 1.285 +} 1.286 + 1.287 +nsresult 1.288 +NS_DumpStatusReporter () 1.289 +{ 1.290 + nsCOMPtr<nsIStatusReporterManager> mgr = 1.291 + do_GetService("@mozilla.org/status-reporter-manager;1"); 1.292 + if (mgr == nullptr) 1.293 + return NS_ERROR_FAILURE; 1.294 + return mgr->DumpReports(); 1.295 +}