Bug 661573 - Telemetry: Do not record/send data in private mode r=Mossop

This commit is contained in:
Taras Glek 2011-06-28 16:57:44 -07:00
parent 6c90dd6553
commit cea0e1bf96
4 changed files with 119 additions and 27 deletions

View File

@ -65,14 +65,22 @@ class TelemetryImpl : public nsITelemetry
public:
TelemetryImpl();
~TelemetryImpl();
static bool CanRecord();
static already_AddRefed<nsITelemetry> CreateTelemetryInstance();
static void ShutdownTelemetry();
private:
// This is used for speedy JS string->Telemetry::ID conversions
typedef nsBaseHashtableET<nsCharPtrHashKey, Telemetry::ID> CharPtrEntryType;
typedef nsTHashtable<CharPtrEntryType> HistogramMapType;
HistogramMapType mHistogramMap;
bool mCanRecord;
static TelemetryImpl *sTelemetry;
};
TelemetryImpl* TelemetryImpl::sTelemetry = NULL;
// A initializer to initialize histogram collection
StatisticsRecorder gStatisticsRecorder;
@ -205,12 +213,14 @@ JSHistogram_Add(JSContext *cx, uintN argc, jsval *vp)
return JS_FALSE;
}
JSObject *obj = JS_THIS_OBJECT(cx, vp);
Histogram *h = static_cast<Histogram*>(JS_GetPrivate(cx, obj));
if (h->histogram_type() == Histogram::BOOLEAN_HISTOGRAM)
h->Add(!!value);
else
h->Add(value);
if (TelemetryImpl::CanRecord()) {
JSObject *obj = JS_THIS_OBJECT(cx, vp);
Histogram *h = static_cast<Histogram*>(JS_GetPrivate(cx, obj));
if (h->histogram_type() == Histogram::BOOLEAN_HISTOGRAM)
h->Add(!!value);
else
h->Add(value);
}
return JS_TRUE;
}
@ -246,7 +256,9 @@ WrapAndReturnHistogram(Histogram *h, JSContext *cx, jsval *ret)
&& JS_DefineFunction (cx, obj, "snapshot", JSHistogram_Snapshot, 1, 0)) ? NS_OK : NS_ERROR_FAILURE;
}
TelemetryImpl::TelemetryImpl() {
TelemetryImpl::TelemetryImpl():
mCanRecord(true)
{
mHistogramMap.Init(Telemetry::HistogramCount);
}
@ -317,16 +329,43 @@ TelemetryImpl::GetHistogramById(const nsACString &name, JSContext *cx, jsval *re
return WrapAndReturnHistogram(h, cx, ret);
}
NS_IMPL_THREADSAFE_ISUPPORTS1(TelemetryImpl, nsITelemetry)
already_AddRefed<nsITelemetry>
CreateTelemetryInstance()
{
nsCOMPtr<nsITelemetry> telemetry = new TelemetryImpl();
return telemetry.forget();
NS_IMETHODIMP
TelemetryImpl::GetCanRecord(PRBool *ret) {
*ret = mCanRecord;
return NS_OK;
}
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsITelemetry, CreateTelemetryInstance)
NS_IMETHODIMP
TelemetryImpl::SetCanRecord(PRBool canRecord) {
mCanRecord = !!canRecord;
return NS_OK;
}
bool
TelemetryImpl::CanRecord() {
return !sTelemetry || sTelemetry->mCanRecord;
}
already_AddRefed<nsITelemetry>
TelemetryImpl::CreateTelemetryInstance()
{
NS_ABORT_IF_FALSE(sTelemetry == NULL, "CreateTelemetryInstance may only be called once, via GetService()");
sTelemetry = new TelemetryImpl();
// AddRef for the local reference
NS_ADDREF(sTelemetry);
// AddRef for the caller
NS_ADDREF(sTelemetry);
return sTelemetry;
}
void
TelemetryImpl::ShutdownTelemetry()
{
NS_IF_RELEASE(sTelemetry);
}
NS_IMPL_THREADSAFE_ISUPPORTS1(TelemetryImpl, nsITelemetry)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsITelemetry, TelemetryImpl::CreateTelemetryInstance)
#define NS_TELEMETRY_CID \
{0xaea477f2, 0xb3a2, 0x469c, {0xaa, 0x29, 0x0a, 0x82, 0xd1, 0x32, 0xb8, 0x29}}
@ -349,7 +388,7 @@ const Module kTelemetryModule = {
NULL,
NULL,
NULL,
NULL,
TelemetryImpl::ShutdownTelemetry
};
} // anonymous namespace
@ -360,6 +399,9 @@ namespace Telemetry {
void
Accumulate(ID aHistogram, PRUint32 aSample)
{
if (!TelemetryImpl::CanRecord()) {
return;
}
Histogram *h;
nsresult rv = GetHistogramByEnumId(aHistogram, &h);
if (NS_SUCCEEDED(rv))

View File

@ -295,6 +295,24 @@ TelemetryPing.prototype = {
request.send(nativeJSON.encode(payload));
},
attachObservers: function attachObservers() {
if (!this._initialized)
return;
let idleService = Cc["@mozilla.org/widget/idleservice;1"].
getService(Ci.nsIIdleService);
idleService.addIdleObserver(this, TELEMETRY_INTERVAL);
Services.obs.addObserver(this, "idle-daily", false);
},
detachObservers: function detachObservers() {
if (!this._initialized)
return;
let idleService = Cc["@mozilla.org/widget/idleservice;1"].
getService(Ci.nsIIdleService);
idleService.removeIdleObserver(this, TELEMETRY_INTERVAL);
Services.obs.removeObserver(this, "idle-daily");
},
/**
* Initializes telemetry within a timer. If there is no PREF_SERVER set, don't turn on telemetry.
*/
@ -306,17 +324,23 @@ TelemetryPing.prototype = {
} catch (e) {
// Prerequesite prefs aren't set
}
if (!enabled)
if (!enabled) {
// Turn off local telemetry if telemetry is disabled.
// This may change once about:telemetry is added.
Telemetry.canRecord = false;
return;
}
Services.obs.addObserver(this, "private-browsing", false);
Services.obs.addObserver(this, "profile-before-change", false);
// Delay full telemetry initialization to give the browser time to
// run various late initializers. Otherwise our gathered memory
// footprint and other numbers would be too optimistic.
let self = this;
this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
let timerCallback = function() {
let idleService = Cc["@mozilla.org/widget/idleservice;1"].
getService(Ci.nsIIdleService);
idleService.addIdleObserver(self, TELEMETRY_INTERVAL);
Services.obs.addObserver(self, "idle-daily", false);
Services.obs.addObserver(self, "profile-before-change", false);
self._initialized = true;
self.attachObservers();
self.gatherMemory();
delete self._timer
}
@ -327,11 +351,9 @@ TelemetryPing.prototype = {
* Remove observers to avoid leaks
*/
uninstall: function uninstall() {
let idleService = Cc["@mozilla.org/widget/idleservice;1"].
getService(Ci.nsIIdleService);
idleService.removeIdleObserver(this, TELEMETRY_INTERVAL);
Services.obs.removeObserver(this, "idle-daily");
this.detachObservers()
Services.obs.removeObserver(this, "profile-before-change");
Services.obs.removeObserver(this, "private-browsing");
},
/**
@ -351,6 +373,14 @@ TelemetryPing.prototype = {
case "idle":
this.gatherMemory();
break;
case "private-browsing":
Telemetry.canRecord = aData == "exit";
if (aData == "enter") {
this.detachObservers()
} else {
this.attachObservers()
}
break;
case "test-ping":
server = aData;
// fall through

View File

@ -87,4 +87,9 @@ interface nsITelemetry : nsISupports
*/
[implicit_jscontext]
jsval getHistogramById(in ACString id);
/**
* Set this to false to disable gathering of telemetry statistics.
*/
attribute boolean canRecord;
};

View File

@ -3,8 +3,10 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
Cu.import("resource://gre/modules/Services.jsm");
function test_histogram(histogram_type, name, min, max, bucket_count) {
var h = Telemetry.newHistogram(name, min, max, bucket_count, histogram_type);
@ -85,6 +87,18 @@ function test_getHistogramById() {
do_check_eq(s.max, 10000);
}
// Check that telemetry doesn't record in private mode
function test_privateMode() {
var h = Telemetry.newHistogram("test::private_mode_boolean", 1,2,3, Telemetry.HISTOGRAM_BOOLEAN);
var orig = h.snapshot();
Telemetry.canRecord = false;
h.add(1);
do_check_eq(uneval(orig), uneval(h.snapshot()));
Telemetry.canRecord = true;
h.add(1);
do_check_neq(uneval(orig), uneval(h.snapshot()));
}
function run_test()
{
let kinds = [Telemetry.HISTOGRAM_EXPONENTIAL, Telemetry.HISTOGRAM_LINEAR]
@ -99,4 +113,5 @@ function run_test()
test_boolean_histogram();
test_getHistogramById();
test_privateMode();
}