michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsTraceRefcnt.h" michael@0: michael@0: // if NS_BUILD_REFCNT_LOGGING isn't defined, don't try to build michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: michael@0: #include "nsAboutBloat.h" michael@0: #include "nsStringStream.h" michael@0: #include "nsIURI.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsDirectoryServiceDefs.h" michael@0: #include "nsIFile.h" michael@0: michael@0: static void GC_gcollect() {} michael@0: michael@0: NS_IMPL_ISUPPORTS(nsAboutBloat, nsIAboutModule) michael@0: michael@0: NS_IMETHODIMP michael@0: nsAboutBloat::NewChannel(nsIURI *aURI, nsIChannel **result) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aURI); michael@0: nsresult rv; michael@0: nsAutoCString path; michael@0: rv = aURI->GetPath(path); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsTraceRefcnt::StatisticsType statType = nsTraceRefcnt::ALL_STATS; michael@0: bool clear = false; michael@0: bool leaks = false; michael@0: michael@0: int32_t pos = path.Find("?"); michael@0: if (pos > 0) { michael@0: nsAutoCString param; michael@0: (void)path.Right(param, path.Length() - (pos+1)); michael@0: if (param.EqualsLiteral("new")) michael@0: statType = nsTraceRefcnt::NEW_STATS; michael@0: else if (param.EqualsLiteral("clear")) michael@0: clear = true; michael@0: else if (param.EqualsLiteral("leaks")) michael@0: leaks = true; michael@0: } michael@0: michael@0: nsCOMPtr inStr; michael@0: if (clear) { michael@0: nsTraceRefcnt::ResetStatistics(); michael@0: michael@0: rv = NS_NewCStringInputStream(getter_AddRefs(inStr), michael@0: NS_LITERAL_CSTRING("Bloat statistics cleared.")); michael@0: if (NS_FAILED(rv)) return rv; michael@0: } michael@0: else if (leaks) { michael@0: // dump the current set of leaks. michael@0: GC_gcollect(); michael@0: michael@0: rv = NS_NewCStringInputStream(getter_AddRefs(inStr), michael@0: NS_LITERAL_CSTRING("Memory leaks dumped.")); michael@0: if (NS_FAILED(rv)) return rv; michael@0: } michael@0: else { michael@0: nsCOMPtr file; michael@0: rv = NS_GetSpecialDirectory(NS_OS_CURRENT_PROCESS_DIR, michael@0: getter_AddRefs(file)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = file->AppendNative(NS_LITERAL_CSTRING("bloatlogs")); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: bool exists; michael@0: rv = file->Exists(&exists); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (!exists) { michael@0: // On all the platforms that I know use permissions, michael@0: // directories need to have the executable flag set michael@0: // if you want to do anything inside the directory. michael@0: rv = file->Create(nsIFile::DIRECTORY_TYPE, 0755); michael@0: if (NS_FAILED(rv)) return rv; michael@0: } michael@0: michael@0: nsAutoCString dumpFileName; michael@0: if (statType == nsTraceRefcnt::ALL_STATS) michael@0: dumpFileName.AssignLiteral("all-"); michael@0: else michael@0: dumpFileName.AssignLiteral("new-"); michael@0: PRExplodedTime expTime; michael@0: PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &expTime); michael@0: char time[128]; michael@0: PR_FormatTimeUSEnglish(time, 128, "%Y-%m-%d-%H%M%S.txt", &expTime); michael@0: dumpFileName += time; michael@0: rv = file->AppendNative(dumpFileName); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: FILE* out; michael@0: rv = file->OpenANSIFileDesc("w", &out); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = nsTraceRefcnt::DumpStatistics(statType, out); michael@0: ::fclose(out); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), file); michael@0: if (NS_FAILED(rv)) return rv; michael@0: } michael@0: michael@0: nsIChannel* channel = nullptr; michael@0: rv = NS_NewInputStreamChannel(&channel, aURI, inStr, michael@0: NS_LITERAL_CSTRING("text/plain"), michael@0: NS_LITERAL_CSTRING("utf-8")); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: *result = channel; michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsAboutBloat::GetURIFlags(nsIURI *aURI, uint32_t *result) michael@0: { michael@0: *result = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsAboutBloat::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) michael@0: { michael@0: nsAboutBloat* about = new nsAboutBloat(); michael@0: if (about == nullptr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: NS_ADDREF(about); michael@0: nsresult rv = about->QueryInterface(aIID, aResult); michael@0: NS_RELEASE(about); michael@0: return rv; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: #endif /* NS_BUILD_REFCNT_LOGGING */