Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <string>
7 #include <sstream>
8 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
9 #include "EventTracer.h"
10 #endif
11 #include "GeckoProfiler.h"
12 #include "nsProfiler.h"
13 #include "nsMemory.h"
14 #include "nsString.h"
15 #include "mozilla/Services.h"
16 #include "nsIObserverService.h"
17 #include "nsIInterfaceRequestor.h"
18 #include "nsILoadContext.h"
19 #include "nsIWebNavigation.h"
20 #include "nsIInterfaceRequestorUtils.h"
21 #include "shared-libraries.h"
22 #include "js/Value.h"
24 using std::string;
26 NS_IMPL_ISUPPORTS(nsProfiler, nsIProfiler)
28 nsProfiler::nsProfiler()
29 : mLockedForPrivateBrowsing(false)
30 {
31 }
33 nsProfiler::~nsProfiler()
34 {
35 nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
36 if (observerService) {
37 observerService->RemoveObserver(this, "chrome-document-global-created");
38 observerService->RemoveObserver(this, "last-pb-context-exited");
39 }
40 }
42 nsresult
43 nsProfiler::Init() {
44 nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
45 if (observerService) {
46 observerService->AddObserver(this, "chrome-document-global-created", false);
47 observerService->AddObserver(this, "last-pb-context-exited", false);
48 }
49 return NS_OK;
50 }
52 NS_IMETHODIMP
53 nsProfiler::Observe(nsISupports *aSubject,
54 const char *aTopic,
55 const char16_t *aData)
56 {
57 if (strcmp(aTopic, "chrome-document-global-created") == 0) {
58 nsCOMPtr<nsIInterfaceRequestor> requestor = do_QueryInterface(aSubject);
59 nsCOMPtr<nsIWebNavigation> parentWebNav = do_GetInterface(requestor);
60 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(parentWebNav);
61 if (loadContext && loadContext->UsePrivateBrowsing() && !mLockedForPrivateBrowsing) {
62 mLockedForPrivateBrowsing = true;
63 profiler_lock();
64 }
65 } else if (strcmp(aTopic, "last-pb-context-exited") == 0) {
66 mLockedForPrivateBrowsing = false;
67 profiler_unlock();
68 }
69 return NS_OK;
70 }
72 NS_IMETHODIMP
73 nsProfiler::StartProfiler(uint32_t aEntries, double aInterval,
74 const char** aFeatures, uint32_t aFeatureCount,
75 const char** aThreadNameFilters, uint32_t aFilterCount)
76 {
77 if (mLockedForPrivateBrowsing) {
78 return NS_ERROR_NOT_AVAILABLE;
79 }
81 profiler_start(aEntries, aInterval,
82 aFeatures, aFeatureCount,
83 aThreadNameFilters, aFilterCount);
84 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
85 bool printToConsole = false;
86 mozilla::InitEventTracing(printToConsole);
87 #endif
88 return NS_OK;
89 }
91 NS_IMETHODIMP
92 nsProfiler::StopProfiler()
93 {
94 profiler_stop();
95 return NS_OK;
96 }
98 NS_IMETHODIMP
99 nsProfiler::IsPaused(bool *aIsPaused)
100 {
101 *aIsPaused = profiler_is_paused();
102 return NS_OK;
103 }
105 NS_IMETHODIMP
106 nsProfiler::PauseSampling()
107 {
108 profiler_pause();
109 return NS_OK;
110 }
112 NS_IMETHODIMP
113 nsProfiler::ResumeSampling()
114 {
115 profiler_resume();
116 return NS_OK;
117 }
119 NS_IMETHODIMP
120 nsProfiler::AddMarker(const char *aMarker)
121 {
122 PROFILER_MARKER(aMarker);
123 return NS_OK;
124 }
126 NS_IMETHODIMP
127 nsProfiler::GetProfile(char **aProfile)
128 {
129 char *profile = profiler_get_profile();
130 if (profile) {
131 size_t len = strlen(profile);
132 char *profileStr = static_cast<char *>
133 (nsMemory::Clone(profile, (len + 1) * sizeof(char)));
134 profileStr[len] = '\0';
135 *aProfile = profileStr;
136 free(profile);
137 }
138 return NS_OK;
139 }
141 static void
142 AddSharedLibraryInfoToStream(std::ostream& aStream, const SharedLibrary& aLib)
143 {
144 aStream << "{";
145 aStream << "\"start\":" << aLib.GetStart();
146 aStream << ",\"end\":" << aLib.GetEnd();
147 aStream << ",\"offset\":" << aLib.GetOffset();
148 aStream << ",\"name\":\"" << aLib.GetName() << "\"";
149 const std::string &breakpadId = aLib.GetBreakpadId();
150 aStream << ",\"breakpadId\":\"" << breakpadId << "\"";
151 #ifdef XP_WIN
152 // FIXME: remove this XP_WIN code when the profiler plugin has switched to
153 // using breakpadId.
154 std::string pdbSignature = breakpadId.substr(0, 32);
155 std::string pdbAgeStr = breakpadId.substr(32, breakpadId.size() - 1);
157 std::stringstream stream;
158 stream << pdbAgeStr;
160 unsigned pdbAge;
161 stream << std::hex;
162 stream >> pdbAge;
164 #ifdef DEBUG
165 std::ostringstream oStream;
166 oStream << pdbSignature << std::hex << std::uppercase << pdbAge;
167 MOZ_ASSERT(breakpadId == oStream.str());
168 #endif
170 aStream << ",\"pdbSignature\":\"" << pdbSignature << "\"";
171 aStream << ",\"pdbAge\":" << pdbAge;
172 aStream << ",\"pdbName\":\"" << aLib.GetName() << "\"";
173 #endif
174 aStream << "}";
175 }
177 std::string
178 GetSharedLibraryInfoString()
179 {
180 SharedLibraryInfo info = SharedLibraryInfo::GetInfoForSelf();
181 if (info.GetSize() == 0)
182 return "[]";
184 std::ostringstream os;
185 os << "[";
186 AddSharedLibraryInfoToStream(os, info.GetEntry(0));
188 for (size_t i = 1; i < info.GetSize(); i++) {
189 os << ",";
190 AddSharedLibraryInfoToStream(os, info.GetEntry(i));
191 }
193 os << "]";
194 return os.str();
195 }
197 NS_IMETHODIMP
198 nsProfiler::GetSharedLibraryInformation(nsAString& aOutString)
199 {
200 aOutString.Assign(NS_ConvertUTF8toUTF16(GetSharedLibraryInfoString().c_str()));
201 return NS_OK;
202 }
204 NS_IMETHODIMP nsProfiler::GetProfileData(JSContext* aCx,
205 JS::MutableHandle<JS::Value> aResult)
206 {
207 JS::RootedObject obj(aCx, profiler_get_profile_jsobject(aCx));
208 if (!obj) {
209 return NS_ERROR_FAILURE;
210 }
211 aResult.setObject(*obj);
212 return NS_OK;
213 }
215 NS_IMETHODIMP
216 nsProfiler::IsActive(bool *aIsActive)
217 {
218 *aIsActive = profiler_is_active();
219 return NS_OK;
220 }
222 NS_IMETHODIMP
223 nsProfiler::GetResponsivenessTimes(uint32_t *aCount, double **aResult)
224 {
225 unsigned int len = 100;
226 const double* times = profiler_get_responsiveness();
227 if (!times) {
228 *aCount = 0;
229 *aResult = nullptr;
230 return NS_OK;
231 }
233 double *fs = static_cast<double *>
234 (nsMemory::Clone(times, len * sizeof(double)));
236 *aCount = len;
237 *aResult = fs;
239 return NS_OK;
240 }
242 NS_IMETHODIMP
243 nsProfiler::GetFeatures(uint32_t *aCount, char ***aFeatures)
244 {
245 uint32_t len = 0;
247 const char **features = profiler_get_features();
248 if (!features) {
249 *aCount = 0;
250 *aFeatures = nullptr;
251 return NS_OK;
252 }
254 while (features[len]) {
255 len++;
256 }
258 char **featureList = static_cast<char **>
259 (nsMemory::Alloc(len * sizeof(char*)));
261 for (size_t i = 0; i < len; i++) {
262 size_t strLen = strlen(features[i]);
263 featureList[i] = static_cast<char *>
264 (nsMemory::Clone(features[i], (strLen + 1) * sizeof(char)));
265 }
267 *aFeatures = featureList;
268 *aCount = len;
269 return NS_OK;
270 }