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 "nsMemoryReporterManager.h"
8 #include "MemoryReportRequest.h"
9 #include "mozilla/ipc/FileDescriptor.h"
10 #include "mozilla/ipc/FileDescriptorUtils.h"
11
12 using namespace mozilla::ipc;
13
14 namespace mozilla {
15 namespace dom {
16
MemoryReportRequestHost(uint32_t aGeneration)17 MemoryReportRequestHost::MemoryReportRequestHost(uint32_t aGeneration)
18 : mGeneration(aGeneration), mSuccess(false) {
19 MOZ_COUNT_CTOR(MemoryReportRequestHost);
20 mReporterManager = nsMemoryReporterManager::GetOrCreate();
21 NS_WARNING_ASSERTION(mReporterManager, "GetOrCreate failed");
22 }
23
RecvReport(const MemoryReport & aReport)24 void MemoryReportRequestHost::RecvReport(const MemoryReport& aReport) {
25 // Skip reports from older generations. We need to do this here since we
26 // could receive older reports from a subprocesses before it acknowledges
27 // a new request, and we only track one active request per process.
28 if (aReport.generation() != mGeneration) {
29 return;
30 }
31
32 if (mReporterManager) {
33 mReporterManager->HandleChildReport(mGeneration, aReport);
34 }
35 }
36
Finish(uint32_t aGeneration)37 void MemoryReportRequestHost::Finish(uint32_t aGeneration) {
38 // Skip reports from older generations. See the comment in RecvReport.
39 if (mGeneration != aGeneration) {
40 return;
41 }
42 mSuccess = true;
43 }
44
~MemoryReportRequestHost()45 MemoryReportRequestHost::~MemoryReportRequestHost() {
46 MOZ_COUNT_DTOR(MemoryReportRequestHost);
47
48 if (mReporterManager) {
49 mReporterManager->EndProcessReport(mGeneration, mSuccess);
50 mReporterManager = nullptr;
51 }
52 }
53
NS_IMPL_ISUPPORTS(MemoryReportRequestClient,nsIRunnable)54 NS_IMPL_ISUPPORTS(MemoryReportRequestClient, nsIRunnable)
55
56 /* static */ void MemoryReportRequestClient::Start(
57 uint32_t aGeneration, bool aAnonymize, bool aMinimizeMemoryUsage,
58 const Maybe<FileDescriptor>& aDMDFile, const nsACString& aProcessString,
59 const ReportCallback& aReportCallback,
60 const FinishCallback& aFinishCallback) {
61 RefPtr<MemoryReportRequestClient> request = new MemoryReportRequestClient(
62 aGeneration, aAnonymize, aDMDFile, aProcessString, aReportCallback,
63 aFinishCallback);
64
65 DebugOnly<nsresult> rv;
66 if (aMinimizeMemoryUsage) {
67 nsCOMPtr<nsIMemoryReporterManager> mgr =
68 do_GetService("@mozilla.org/memory-reporter-manager;1");
69 rv = mgr->MinimizeMemoryUsage(request);
70 // mgr will eventually call actor->Run()
71 } else {
72 rv = request->Run();
73 }
74
75 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "actor operation failed");
76 }
77
MemoryReportRequestClient(uint32_t aGeneration,bool aAnonymize,const Maybe<FileDescriptor> & aDMDFile,const nsACString & aProcessString,const ReportCallback & aReportCallback,const FinishCallback & aFinishCallback)78 MemoryReportRequestClient::MemoryReportRequestClient(
79 uint32_t aGeneration, bool aAnonymize,
80 const Maybe<FileDescriptor>& aDMDFile, const nsACString& aProcessString,
81 const ReportCallback& aReportCallback,
82 const FinishCallback& aFinishCallback)
83 : mGeneration(aGeneration),
84 mAnonymize(aAnonymize),
85 mProcessString(aProcessString),
86 mReportCallback(aReportCallback),
87 mFinishCallback(aFinishCallback) {
88 if (aDMDFile.isSome()) {
89 mDMDFile = aDMDFile.value();
90 }
91 }
92
93 MemoryReportRequestClient::~MemoryReportRequestClient() = default;
94
95 class HandleReportCallback final : public nsIHandleReportCallback {
96 public:
97 using ReportCallback = typename MemoryReportRequestClient::ReportCallback;
98
99 NS_DECL_ISUPPORTS
100
HandleReportCallback(uint32_t aGeneration,const nsACString & aProcess,const ReportCallback & aReportCallback)101 explicit HandleReportCallback(uint32_t aGeneration,
102 const nsACString& aProcess,
103 const ReportCallback& aReportCallback)
104 : mGeneration(aGeneration),
105 mProcess(aProcess),
106 mReportCallback(aReportCallback) {}
107
Callback(const nsACString & aProcess,const nsACString & aPath,int32_t aKind,int32_t aUnits,int64_t aAmount,const nsACString & aDescription,nsISupports * aUnused)108 NS_IMETHOD Callback(const nsACString& aProcess, const nsACString& aPath,
109 int32_t aKind, int32_t aUnits, int64_t aAmount,
110 const nsACString& aDescription,
111 nsISupports* aUnused) override {
112 MemoryReport memreport(mProcess, nsCString(aPath), aKind, aUnits, aAmount,
113 mGeneration, nsCString(aDescription));
114 mReportCallback(memreport);
115 return NS_OK;
116 }
117
118 private:
119 ~HandleReportCallback() = default;
120
121 uint32_t mGeneration;
122 const nsCString mProcess;
123 ReportCallback mReportCallback;
124 };
125
126 NS_IMPL_ISUPPORTS(HandleReportCallback, nsIHandleReportCallback)
127
128 class FinishReportingCallback final : public nsIFinishReportingCallback {
129 public:
130 using FinishCallback = typename MemoryReportRequestClient::FinishCallback;
131
132 NS_DECL_ISUPPORTS
133
FinishReportingCallback(uint32_t aGeneration,const FinishCallback & aFinishCallback)134 explicit FinishReportingCallback(uint32_t aGeneration,
135 const FinishCallback& aFinishCallback)
136 : mGeneration(aGeneration), mFinishCallback(aFinishCallback) {}
137
Callback(nsISupports * aUnused)138 NS_IMETHOD Callback(nsISupports* aUnused) override {
139 return mFinishCallback(mGeneration) ? NS_OK : NS_ERROR_FAILURE;
140 }
141
142 private:
143 ~FinishReportingCallback() = default;
144
145 uint32_t mGeneration;
146 FinishCallback mFinishCallback;
147 };
148
NS_IMPL_ISUPPORTS(FinishReportingCallback,nsIFinishReportingCallback)149 NS_IMPL_ISUPPORTS(FinishReportingCallback, nsIFinishReportingCallback)
150
151 NS_IMETHODIMP MemoryReportRequestClient::Run() {
152 nsCOMPtr<nsIMemoryReporterManager> mgr =
153 do_GetService("@mozilla.org/memory-reporter-manager;1");
154
155 // Run the reporters. The callback will turn each measurement into a
156 // MemoryReport.
157 RefPtr<HandleReportCallback> handleReport =
158 new HandleReportCallback(mGeneration, mProcessString, mReportCallback);
159 RefPtr<FinishReportingCallback> finishReporting =
160 new FinishReportingCallback(mGeneration, mFinishCallback);
161
162 nsresult rv = mgr->GetReportsForThisProcessExtended(
163 handleReport, nullptr, mAnonymize, FileDescriptorToFILE(mDMDFile, "wb"),
164 finishReporting, nullptr);
165 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
166 "GetReportsForThisProcessExtended failed");
167 return rv;
168 }
169
170 } // namespace dom
171 } // namespace mozilla
172