зеркало из https://github.com/mozilla/gecko-dev.git
Back out bug 707320 (revs 5a315a55ea7e, 6c2b90a11ea8, 5c40a413d9a9, 51bffa83d14f) due to startup crashes (e.g. bug 722545). r=froydnj
This commit is contained in:
Родитель
3b3f03f5ef
Коммит
f07116a13e
|
@ -38,7 +38,6 @@
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
#include "base/histogram.h"
|
#include "base/histogram.h"
|
||||||
#include "base/pickle.h"
|
|
||||||
#include "nsIComponentManager.h"
|
#include "nsIComponentManager.h"
|
||||||
#include "nsIServiceManager.h"
|
#include "nsIServiceManager.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
@ -48,8 +47,6 @@
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "nsStringGlue.h"
|
#include "nsStringGlue.h"
|
||||||
#include "nsITelemetry.h"
|
#include "nsITelemetry.h"
|
||||||
#include "nsIFile.h"
|
|
||||||
#include "nsILocalFile.h"
|
|
||||||
#include "Telemetry.h"
|
#include "Telemetry.h"
|
||||||
#include "nsTHashtable.h"
|
#include "nsTHashtable.h"
|
||||||
#include "nsHashKeys.h"
|
#include "nsHashKeys.h"
|
||||||
|
@ -57,7 +54,6 @@
|
||||||
#include "nsXULAppAPI.h"
|
#include "nsXULAppAPI.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
#include "mozilla/Mutex.h"
|
#include "mozilla/Mutex.h"
|
||||||
#include "mozilla/FileUtils.h"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -231,9 +227,11 @@ enum reflectStatus {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum reflectStatus
|
enum reflectStatus
|
||||||
ReflectHistogramAndSamples(JSContext *cx, JSObject *obj, Histogram *h,
|
ReflectHistogramSnapshot(JSContext *cx, JSObject *obj, Histogram *h)
|
||||||
const Histogram::SampleSet &ss)
|
|
||||||
{
|
{
|
||||||
|
Histogram::SampleSet ss;
|
||||||
|
h->SnapshotSample(&ss);
|
||||||
|
|
||||||
// We don't want to reflect corrupt histograms.
|
// We don't want to reflect corrupt histograms.
|
||||||
if (h->FindCorruption(ss) != Histogram::NO_INCONSISTENCIES) {
|
if (h->FindCorruption(ss) != Histogram::NO_INCONSISTENCIES) {
|
||||||
return REFLECT_CORRUPT;
|
return REFLECT_CORRUPT;
|
||||||
|
@ -262,14 +260,6 @@ ReflectHistogramAndSamples(JSContext *cx, JSObject *obj, Histogram *h,
|
||||||
return REFLECT_OK;
|
return REFLECT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum reflectStatus
|
|
||||||
ReflectHistogramSnapshot(JSContext *cx, JSObject *obj, Histogram *h)
|
|
||||||
{
|
|
||||||
Histogram::SampleSet ss;
|
|
||||||
h->SnapshotSample(&ss);
|
|
||||||
return ReflectHistogramAndSamples(cx, obj, h, ss);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
JSHistogram_Add(JSContext *cx, uintN argc, jsval *vp)
|
JSHistogram_Add(JSContext *cx, uintN argc, jsval *vp)
|
||||||
{
|
{
|
||||||
|
@ -687,333 +677,6 @@ TelemetryImpl::GetHistogramById(const nsACString &name, JSContext *cx, jsval *re
|
||||||
return WrapAndReturnHistogram(h, cx, ret);
|
return WrapAndReturnHistogram(h, cx, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
class TelemetrySessionData : public nsITelemetrySessionData
|
|
||||||
{
|
|
||||||
NS_DECL_ISUPPORTS
|
|
||||||
NS_DECL_NSITELEMETRYSESSIONDATA
|
|
||||||
|
|
||||||
public:
|
|
||||||
static nsresult LoadFromDisk(nsIFile *, TelemetrySessionData **ptr);
|
|
||||||
static nsresult SaveToDisk(nsIFile *, const nsACString &uuid);
|
|
||||||
|
|
||||||
TelemetrySessionData(const char *uuid);
|
|
||||||
~TelemetrySessionData();
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct EnumeratorArgs {
|
|
||||||
JSContext *cx;
|
|
||||||
JSObject *snapshots;
|
|
||||||
};
|
|
||||||
typedef nsBaseHashtableET<nsUint32HashKey, Histogram::SampleSet> EntryType;
|
|
||||||
typedef nsTHashtable<EntryType> SessionMapType;
|
|
||||||
static PLDHashOperator ReflectSamples(EntryType *entry, void *arg);
|
|
||||||
SessionMapType mSampleSetMap;
|
|
||||||
nsCString mUUID;
|
|
||||||
|
|
||||||
bool DeserializeHistogramData(Pickle &pickle, void **iter);
|
|
||||||
static bool SerializeHistogramData(Pickle &pickle);
|
|
||||||
|
|
||||||
// The file format version. Should be incremented whenever we change
|
|
||||||
// how individual SampleSets are stored in the file.
|
|
||||||
static const unsigned int sVersion = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
NS_IMPL_THREADSAFE_ISUPPORTS1(TelemetrySessionData, nsITelemetrySessionData)
|
|
||||||
|
|
||||||
TelemetrySessionData::TelemetrySessionData(const char *uuid)
|
|
||||||
: mUUID(uuid)
|
|
||||||
{
|
|
||||||
mSampleSetMap.Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
TelemetrySessionData::~TelemetrySessionData()
|
|
||||||
{
|
|
||||||
mSampleSetMap.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
TelemetrySessionData::GetUuid(nsACString &uuid)
|
|
||||||
{
|
|
||||||
uuid = mUUID;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
PLDHashOperator
|
|
||||||
TelemetrySessionData::ReflectSamples(EntryType *entry, void *arg)
|
|
||||||
{
|
|
||||||
struct EnumeratorArgs *args = static_cast<struct EnumeratorArgs *>(arg);
|
|
||||||
// This has the undesirable effect of creating a histogram for the
|
|
||||||
// current session with the given ID. But there's no good way to
|
|
||||||
// compute the ranges and buckets from scratch.
|
|
||||||
Histogram *h = nsnull;
|
|
||||||
nsresult rv = GetHistogramByEnumId(Telemetry::ID(entry->GetKey()), &h);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return PL_DHASH_STOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't reflect histograms with no data associated with them.
|
|
||||||
if (entry->mData.sum() == 0) {
|
|
||||||
return PL_DHASH_NEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject *snapshot = JS_NewObject(args->cx, NULL, NULL, NULL);
|
|
||||||
if (!(snapshot
|
|
||||||
&& ReflectHistogramAndSamples(args->cx, snapshot, h, entry->mData)
|
|
||||||
&& JS_DefineProperty(args->cx, args->snapshots,
|
|
||||||
h->histogram_name().c_str(),
|
|
||||||
OBJECT_TO_JSVAL(snapshot), NULL, NULL,
|
|
||||||
JSPROP_ENUMERATE))) {
|
|
||||||
return PL_DHASH_STOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
return PL_DHASH_NEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
TelemetrySessionData::GetSnapshots(JSContext *cx, jsval *ret)
|
|
||||||
{
|
|
||||||
JSObject *snapshots = JS_NewObject(cx, NULL, NULL, NULL);
|
|
||||||
if (!snapshots) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct EnumeratorArgs args = { cx, snapshots };
|
|
||||||
PRUint32 count = mSampleSetMap.EnumerateEntries(ReflectSamples,
|
|
||||||
static_cast<void*>(&args));
|
|
||||||
if (count != mSampleSetMap.Count()) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
*ret = OBJECT_TO_JSVAL(snapshots);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TelemetrySessionData::DeserializeHistogramData(Pickle &pickle, void **iter)
|
|
||||||
{
|
|
||||||
PRUint32 count = 0;
|
|
||||||
if (!pickle.ReadUInt32(iter, &count)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
int stored_length;
|
|
||||||
const char *name;
|
|
||||||
if (!pickle.ReadData(iter, &name, &stored_length)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Telemetry::ID id;
|
|
||||||
nsresult rv = TelemetryImpl::GetHistogramEnumId(name, &id);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
// We serialized a non-static histogram. Just drop its data on
|
|
||||||
// the floor. If we can't deserialize the data, though, we're in
|
|
||||||
// trouble.
|
|
||||||
Histogram::SampleSet ss;
|
|
||||||
if (!ss.Deserialize(iter, pickle)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EntryType *entry = mSampleSetMap.GetEntry(id);
|
|
||||||
if (!entry) {
|
|
||||||
entry = mSampleSetMap.PutEntry(id);
|
|
||||||
if (NS_UNLIKELY(!entry)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!entry->mData.Deserialize(iter, pickle)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
TelemetrySessionData::LoadFromDisk(nsIFile *file, TelemetrySessionData **ptr)
|
|
||||||
{
|
|
||||||
*ptr = nsnull;
|
|
||||||
nsresult rv;
|
|
||||||
nsCOMPtr<nsILocalFile> f(do_QueryInterface(file, &rv));
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoFDClose fd;
|
|
||||||
rv = f->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRInt32 size = PR_Available(fd);
|
|
||||||
if (size == -1) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoArrayPtr<char> data(new char[size]);
|
|
||||||
PRInt32 amount = PR_Read(fd, data, size);
|
|
||||||
if (amount != size) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pickle pickle(data, size);
|
|
||||||
void *iter = NULL;
|
|
||||||
|
|
||||||
unsigned int storedVersion;
|
|
||||||
if (!(pickle.ReadUInt32(&iter, &storedVersion)
|
|
||||||
&& storedVersion == sVersion)) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *uuid;
|
|
||||||
int uuidLength;
|
|
||||||
if (!pickle.ReadData(&iter, &uuid, &uuidLength)) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoPtr<TelemetrySessionData> sessionData(new TelemetrySessionData(uuid));
|
|
||||||
if (!sessionData->DeserializeHistogramData(pickle, &iter)) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
*ptr = sessionData.forget();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TelemetrySessionData::SerializeHistogramData(Pickle &pickle)
|
|
||||||
{
|
|
||||||
StatisticsRecorder::Histograms hs;
|
|
||||||
StatisticsRecorder::GetHistograms(&hs);
|
|
||||||
|
|
||||||
if (!pickle.WriteUInt32(hs.size())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (StatisticsRecorder::Histograms::const_iterator it = hs.begin();
|
|
||||||
it != hs.end();
|
|
||||||
++it) {
|
|
||||||
const Histogram *h = *it;
|
|
||||||
const char *name = h->histogram_name().c_str();
|
|
||||||
|
|
||||||
Histogram::SampleSet ss;
|
|
||||||
h->SnapshotSample(&ss);
|
|
||||||
|
|
||||||
if (!(pickle.WriteData(name, strlen(name)+1)
|
|
||||||
&& ss.Serialize(&pickle))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
TelemetrySessionData::SaveToDisk(nsIFile *file, const nsACString &uuid)
|
|
||||||
{
|
|
||||||
nsresult rv;
|
|
||||||
nsCOMPtr<nsILocalFile> f(do_QueryInterface(file, &rv));
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoFDClose fd;
|
|
||||||
rv = f->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pickle pickle;
|
|
||||||
if (!pickle.WriteUInt32(sVersion)) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Include the trailing NULL for the UUID to make reading easier.
|
|
||||||
const char *data;
|
|
||||||
size_t length = uuid.GetData(&data);
|
|
||||||
if (!(pickle.WriteData(data, length+1)
|
|
||||||
&& SerializeHistogramData(pickle))) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRInt32 amount = PR_Write(fd, static_cast<const char*>(pickle.data()),
|
|
||||||
pickle.size());
|
|
||||||
if (amount != pickle.size()) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
class SaveHistogramEvent : public nsRunnable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SaveHistogramEvent(nsIFile *file, const nsACString &uuid,
|
|
||||||
nsITelemetrySaveSessionDataCallback *callback)
|
|
||||||
: mFile(file), mUUID(uuid), mCallback(callback)
|
|
||||||
{}
|
|
||||||
|
|
||||||
NS_IMETHOD Run()
|
|
||||||
{
|
|
||||||
nsresult rv = TelemetrySessionData::SaveToDisk(mFile, mUUID);
|
|
||||||
mCallback->Handle(!!NS_SUCCEEDED(rv));
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsCOMPtr<nsIFile> mFile;
|
|
||||||
nsCString mUUID;
|
|
||||||
nsCOMPtr<nsITelemetrySaveSessionDataCallback> mCallback;
|
|
||||||
};
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
TelemetryImpl::SaveHistograms(nsIFile *file, const nsACString &uuid,
|
|
||||||
nsITelemetrySaveSessionDataCallback *callback,
|
|
||||||
bool isSynchronous)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIRunnable> event = new SaveHistogramEvent(file, uuid, callback);
|
|
||||||
if (isSynchronous) {
|
|
||||||
return event ? event->Run() : NS_ERROR_FAILURE;
|
|
||||||
} else {
|
|
||||||
return NS_DispatchToCurrentThread(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LoadHistogramEvent : public nsRunnable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LoadHistogramEvent(nsIFile *file,
|
|
||||||
nsITelemetryLoadSessionDataCallback *callback)
|
|
||||||
: mFile(file), mCallback(callback)
|
|
||||||
{}
|
|
||||||
|
|
||||||
NS_IMETHOD Run()
|
|
||||||
{
|
|
||||||
TelemetrySessionData *sessionData = nsnull;
|
|
||||||
nsresult rv = TelemetrySessionData::LoadFromDisk(mFile, &sessionData);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
mCallback->Handle(nsnull);
|
|
||||||
} else {
|
|
||||||
nsCOMPtr<nsITelemetrySessionData> data(sessionData);
|
|
||||||
mCallback->Handle(data);
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsCOMPtr<nsIFile> mFile;
|
|
||||||
nsCOMPtr<nsITelemetryLoadSessionDataCallback> mCallback;
|
|
||||||
};
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
TelemetryImpl::LoadHistograms(nsIFile *file,
|
|
||||||
nsITelemetryLoadSessionDataCallback *callback)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIRunnable> event = new LoadHistogramEvent(file, callback);
|
|
||||||
return NS_DispatchToCurrentThread(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
TelemetryImpl::GetCanRecord(bool *ret) {
|
TelemetryImpl::GetCanRecord(bool *ret) {
|
||||||
*ret = mCanRecord;
|
*ret = mCanRecord;
|
||||||
|
|
|
@ -42,7 +42,6 @@ const Cu = Components.utils;
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
|
Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
|
||||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
|
||||||
|
|
||||||
// When modifying the payload in incompatible ways, please bump this version number
|
// When modifying the payload in incompatible ways, please bump this version number
|
||||||
const PAYLOAD_VERSION = 1;
|
const PAYLOAD_VERSION = 1;
|
||||||
|
@ -180,10 +179,6 @@ TelemetryPing.prototype = {
|
||||||
_histograms: {},
|
_histograms: {},
|
||||||
_initialized: false,
|
_initialized: false,
|
||||||
_prevValues: {},
|
_prevValues: {},
|
||||||
// Generate a unique id once per session so the server can cope with
|
|
||||||
// duplicate submissions.
|
|
||||||
_uuid: generateUUID(),
|
|
||||||
_prevSession: null,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a set of histograms that can be converted into JSON
|
* Returns a set of histograms that can be converted into JSON
|
||||||
|
@ -192,7 +187,8 @@ TelemetryPing.prototype = {
|
||||||
* histogram_type: <0 for exponential, 1 for linear>, bucketX:countX, ....} ...}
|
* histogram_type: <0 for exponential, 1 for linear>, bucketX:countX, ....} ...}
|
||||||
* where bucket[XY], count[XY] are positive integers.
|
* where bucket[XY], count[XY] are positive integers.
|
||||||
*/
|
*/
|
||||||
getHistograms: function getHistograms(hls) {
|
getHistograms: function getHistograms() {
|
||||||
|
let hls = Telemetry.histogramSnapshots;
|
||||||
let info = Telemetry.registeredHistograms;
|
let info = Telemetry.registeredHistograms;
|
||||||
let ret = {};
|
let ret = {};
|
||||||
|
|
||||||
|
@ -401,48 +397,24 @@ TelemetryPing.prototype = {
|
||||||
send: function send(reason, server) {
|
send: function send(reason, server) {
|
||||||
// populate histograms one last time
|
// populate histograms one last time
|
||||||
this.gatherMemory();
|
this.gatherMemory();
|
||||||
let data = this.getSessionPayloadAndSlug(reason);
|
|
||||||
|
|
||||||
// Don't record a successful ping for previous session data.
|
|
||||||
this.doPing(server, data.slug, data.payload, !data.previous);
|
|
||||||
this._prevSession = null;
|
|
||||||
|
|
||||||
// We were sending off data from before; now send the actual data
|
|
||||||
// we've collected this session.
|
|
||||||
if (data.previous) {
|
|
||||||
data = this.getSessionPayloadAndSlug(reason);
|
|
||||||
this.doPing(server, data.slug, data.payload, true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getSessionPayloadAndSlug: function getSessionPayloadAndSlug(reason) {
|
|
||||||
// Use a deterministic url for testing.
|
|
||||||
let isTestPing = (reason == "test-ping");
|
|
||||||
let havePreviousSession = !!this._prevSession;
|
|
||||||
let slug = (isTestPing
|
|
||||||
? reason
|
|
||||||
: (havePreviousSession
|
|
||||||
? this._prevSession.uuid
|
|
||||||
: this._uuid));
|
|
||||||
let payloadObj = {
|
let payloadObj = {
|
||||||
ver: PAYLOAD_VERSION,
|
ver: PAYLOAD_VERSION,
|
||||||
// Send a different reason string for previous session data.
|
info: this.getMetadata(reason),
|
||||||
info: this.getMetadata(havePreviousSession ? "saved-session" : reason),
|
simpleMeasurements: getSimpleMeasurements(),
|
||||||
|
histograms: this.getHistograms(),
|
||||||
|
slowSQL: Telemetry.slowSQL
|
||||||
};
|
};
|
||||||
if (havePreviousSession) {
|
|
||||||
payloadObj.histograms = this.getHistograms(this._prevSession.snapshots);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
payloadObj.simpleMeasurements = getSimpleMeasurements();
|
|
||||||
payloadObj.histograms = this.getHistograms(Telemetry.histogramSnapshots);
|
|
||||||
payloadObj.slowSQL = Telemetry.slowSQL;
|
|
||||||
}
|
|
||||||
return { previous: !!havePreviousSession, slug: slug, payload: JSON.stringify(payloadObj) };
|
|
||||||
},
|
|
||||||
|
|
||||||
doPing: function doPing(server, slug, payload, recordSuccess) {
|
let isTestPing = (reason == "test-ping");
|
||||||
let submitPath = "/submit/telemetry/" + slug;
|
// Generate a unique id once per session so the server can cope with duplicate submissions.
|
||||||
let url = server + submitPath;
|
// Use a deterministic url for testing.
|
||||||
|
if (!this._path)
|
||||||
|
this._path = "/submit/telemetry/" + (isTestPing ? reason : generateUUID());
|
||||||
|
|
||||||
|
let hping = Telemetry.getHistogramById("TELEMETRY_PING");
|
||||||
|
let hsuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
|
||||||
|
|
||||||
|
let url = server + this._path;
|
||||||
let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||||
.createInstance(Ci.nsIXMLHttpRequest);
|
.createInstance(Ci.nsIXMLHttpRequest);
|
||||||
request.mozBackgroundRequest = true;
|
request.mozBackgroundRequest = true;
|
||||||
|
@ -451,7 +423,6 @@ TelemetryPing.prototype = {
|
||||||
request.setRequestHeader("Content-Type", "application/json");
|
request.setRequestHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
let startTime = new Date();
|
let startTime = new Date();
|
||||||
let file = this.savedHistogramsFile();
|
|
||||||
|
|
||||||
function finishRequest(channel) {
|
function finishRequest(channel) {
|
||||||
let success = false;
|
let success = false;
|
||||||
|
@ -459,23 +430,15 @@ TelemetryPing.prototype = {
|
||||||
success = channel.QueryInterface(Ci.nsIHttpChannel).requestSucceeded;
|
success = channel.QueryInterface(Ci.nsIHttpChannel).requestSucceeded;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
}
|
}
|
||||||
if (recordSuccess) {
|
hsuccess.add(success);
|
||||||
let hping = Telemetry.getHistogramById("TELEMETRY_PING");
|
hping.add(new Date() - startTime);
|
||||||
let hsuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
|
if (isTestPing)
|
||||||
|
|
||||||
hsuccess.add(success);
|
|
||||||
hping.add(new Date() - startTime);
|
|
||||||
}
|
|
||||||
if (success && file.exists()) {
|
|
||||||
file.remove(true);
|
|
||||||
}
|
|
||||||
if (slug == "test-ping")
|
|
||||||
Services.obs.notifyObservers(null, "telemetry-test-xhr-complete", null);
|
Services.obs.notifyObservers(null, "telemetry-test-xhr-complete", null);
|
||||||
}
|
}
|
||||||
request.addEventListener("error", function(aEvent) finishRequest(request.channel), false);
|
request.addEventListener("error", function(aEvent) finishRequest(request.channel), false);
|
||||||
request.addEventListener("load", function(aEvent) finishRequest(request.channel), false);
|
request.addEventListener("load", function(aEvent) finishRequest(request.channel), false);
|
||||||
|
|
||||||
request.send(payload);
|
request.send(JSON.stringify(payloadObj));
|
||||||
},
|
},
|
||||||
|
|
||||||
attachObservers: function attachObservers() {
|
attachObservers: function attachObservers() {
|
||||||
|
@ -496,25 +459,6 @@ TelemetryPing.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
savedHistogramsFile: function savedHistogramsFile() {
|
|
||||||
let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
|
|
||||||
let profileFile = profileDirectory.clone();
|
|
||||||
|
|
||||||
// There's a bunch of binary data in the file, so we need to be
|
|
||||||
// sensitive to multiple machine types. Use ctypes to get some
|
|
||||||
// discriminating information.
|
|
||||||
let size = ctypes.voidptr_t.size;
|
|
||||||
// Hack to figure out endianness.
|
|
||||||
let uint32_array_t = ctypes.uint32_t.array(1);
|
|
||||||
let array = uint32_array_t([0xdeadbeef]);
|
|
||||||
let uint8_array_t = ctypes.uint8_t.array(4);
|
|
||||||
let array_as_bytes = ctypes.cast(array, uint8_array_t);
|
|
||||||
let endian = (array_as_bytes[0] === 0xde) ? "big" : "little"
|
|
||||||
let name = "sessionHistograms.dat." + size + endian;
|
|
||||||
profileFile.append(name);
|
|
||||||
return profileFile;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes telemetry within a timer. If there is no PREF_SERVER set, don't turn on telemetry.
|
* Initializes telemetry within a timer. If there is no PREF_SERVER set, don't turn on telemetry.
|
||||||
*/
|
*/
|
||||||
|
@ -535,7 +479,6 @@ TelemetryPing.prototype = {
|
||||||
Services.obs.addObserver(this, "private-browsing", false);
|
Services.obs.addObserver(this, "private-browsing", false);
|
||||||
Services.obs.addObserver(this, "profile-before-change", false);
|
Services.obs.addObserver(this, "profile-before-change", false);
|
||||||
Services.obs.addObserver(this, "sessionstore-windows-restored", false);
|
Services.obs.addObserver(this, "sessionstore-windows-restored", false);
|
||||||
Services.obs.addObserver(this, "quit-application-granted", false);
|
|
||||||
|
|
||||||
// Delay full telemetry initialization to give the browser time to
|
// Delay full telemetry initialization to give the browser time to
|
||||||
// run various late initializers. Otherwise our gathered memory
|
// run various late initializers. Otherwise our gathered memory
|
||||||
|
@ -549,12 +492,6 @@ TelemetryPing.prototype = {
|
||||||
delete self._timer
|
delete self._timer
|
||||||
}
|
}
|
||||||
this._timer.initWithCallback(timerCallback, TELEMETRY_DELAY, Ci.nsITimer.TYPE_ONE_SHOT);
|
this._timer.initWithCallback(timerCallback, TELEMETRY_DELAY, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||||
|
|
||||||
// Load data from the previous session.
|
|
||||||
let loadCallback = function(data) {
|
|
||||||
self._prevSession = data;
|
|
||||||
}
|
|
||||||
Telemetry.loadHistograms(this.savedHistogramsFile(), loadCallback);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -565,7 +502,6 @@ TelemetryPing.prototype = {
|
||||||
Services.obs.removeObserver(this, "sessionstore-windows-restored");
|
Services.obs.removeObserver(this, "sessionstore-windows-restored");
|
||||||
Services.obs.removeObserver(this, "profile-before-change");
|
Services.obs.removeObserver(this, "profile-before-change");
|
||||||
Services.obs.removeObserver(this, "private-browsing");
|
Services.obs.removeObserver(this, "private-browsing");
|
||||||
Services.obs.removeObserver(this, "quit-application-granted");
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -631,11 +567,6 @@ TelemetryPing.prototype = {
|
||||||
}
|
}
|
||||||
this.send(aTopic == "idle" ? "idle-daily" : aTopic, server);
|
this.send(aTopic == "idle" ? "idle-daily" : aTopic, server);
|
||||||
break;
|
break;
|
||||||
case "quit-application-granted":
|
|
||||||
Telemetry.saveHistograms(this.savedHistogramsFile(),
|
|
||||||
this._uuid, function (success) success,
|
|
||||||
/*isSynchronous=*/true);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -38,39 +38,8 @@
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
#include "nsIFile.idl"
|
|
||||||
|
|
||||||
[scriptable, uuid(c177b6b0-5ef1-44f5-bc67-6bcf7d2518e5)]
|
[scriptable, uuid(db854295-478d-4de9-8211-d73ed7d81cd0)]
|
||||||
interface nsITelemetrySessionData : nsISupports
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The UUID of our previous session.
|
|
||||||
*/
|
|
||||||
readonly attribute ACString uuid;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An object containing a snapshot from all registered histograms that had
|
|
||||||
* data recorded in the previous session.
|
|
||||||
* { name1: data1, name2: data2, .... }
|
|
||||||
* where the individual dataN are as nsITelemetry.histogramSnapshots.
|
|
||||||
*/
|
|
||||||
[implicit_jscontext]
|
|
||||||
readonly attribute jsval snapshots;
|
|
||||||
};
|
|
||||||
|
|
||||||
[scriptable, function, uuid(aff36c9d-7e4c-41ab-a9b6-53773bbca0cd)]
|
|
||||||
interface nsITelemetryLoadSessionDataCallback : nsISupports
|
|
||||||
{
|
|
||||||
void handle(in nsITelemetrySessionData data);
|
|
||||||
};
|
|
||||||
|
|
||||||
[scriptable, function, uuid(40065f26-afd2-4417-93de-c1de9adb1548)]
|
|
||||||
interface nsITelemetrySaveSessionDataCallback : nsISupports
|
|
||||||
{
|
|
||||||
void handle(in bool success);
|
|
||||||
};
|
|
||||||
|
|
||||||
[scriptable, uuid(22fc825e-288f-457e-80d5-5bb35f06d37e)]
|
|
||||||
interface nsITelemetry : nsISupports
|
interface nsITelemetry : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -158,34 +127,6 @@ interface nsITelemetry : nsISupports
|
||||||
[implicit_jscontext]
|
[implicit_jscontext]
|
||||||
jsval getHistogramById(in ACString id);
|
jsval getHistogramById(in ACString id);
|
||||||
|
|
||||||
/**
|
|
||||||
* Save persistent histograms to the given file.
|
|
||||||
*
|
|
||||||
* @param file - filename for saving
|
|
||||||
* @param uuid - UUID of this session
|
|
||||||
* @param callback - function to be caled when file writing is complete
|
|
||||||
* @param isSynchronous - whether the save is done synchronously. Defaults
|
|
||||||
* to asynchronous saving.
|
|
||||||
*/
|
|
||||||
void saveHistograms(in nsIFile file, in ACString uuid,
|
|
||||||
in nsITelemetrySaveSessionDataCallback callback,
|
|
||||||
[optional] in boolean isSynchronous);
|
|
||||||
|
|
||||||
/* Reconstruct an nsITelemetryDataSession object containing histogram
|
|
||||||
* information from the given file; the file must have been produced
|
|
||||||
* via saveHistograms. The file is read asynchronously.
|
|
||||||
*
|
|
||||||
* This method does not modify the histogram information being
|
|
||||||
* collected in the current session.
|
|
||||||
*
|
|
||||||
* The reconstructed object is then passed to the given callback.
|
|
||||||
*
|
|
||||||
* @param file - the file to load histogram information from
|
|
||||||
* @param callback - function to process histogram information
|
|
||||||
*/
|
|
||||||
void loadHistograms(in nsIFile file,
|
|
||||||
in nsITelemetryLoadSessionDataCallback callback);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set this to false to disable gathering of telemetry statistics.
|
* Set this to false to disable gathering of telemetry statistics.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -105,45 +105,6 @@ function test_privateMode() {
|
||||||
do_check_neq(uneval(orig), uneval(h.snapshot()));
|
do_check_neq(uneval(orig), uneval(h.snapshot()));
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateUUID() {
|
|
||||||
let str = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString();
|
|
||||||
// strip {}
|
|
||||||
return str.substring(1, str.length - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that we do sane things when saving to disk.
|
|
||||||
function test_loadSave()
|
|
||||||
{
|
|
||||||
let dirService = Cc["@mozilla.org/file/directory_service;1"]
|
|
||||||
.getService(Ci.nsIProperties);
|
|
||||||
let tmpDir = dirService.get("TmpD", Ci.nsILocalFile);
|
|
||||||
let tmpFile = tmpDir.clone();
|
|
||||||
tmpFile.append("saved-histograms.dat");
|
|
||||||
if (tmpFile.exists()) {
|
|
||||||
tmpFile.remove(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
let saveFinished = false;
|
|
||||||
let loadFinished = false;
|
|
||||||
let uuid = generateUUID();
|
|
||||||
let loadCallback = function(data) {
|
|
||||||
do_check_true(data != null);
|
|
||||||
do_check_eq(uuid, data.uuid);
|
|
||||||
loadFinished = true;
|
|
||||||
do_test_finished();
|
|
||||||
};
|
|
||||||
let saveCallback = function(success) {
|
|
||||||
do_check_true(success);
|
|
||||||
Telemetry.loadHistograms(tmpFile, loadCallback);
|
|
||||||
saveFinished = true;
|
|
||||||
};
|
|
||||||
do_test_pending();
|
|
||||||
Telemetry.saveHistograms(tmpFile, uuid, saveCallback);
|
|
||||||
do_register_cleanup(function () do_check_true(saveFinished));
|
|
||||||
do_register_cleanup(function () do_check_true(loadFinished));
|
|
||||||
do_register_cleanup(function () tmpFile.exists() && tmpFile.remove(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_test()
|
function run_test()
|
||||||
{
|
{
|
||||||
let kinds = [Telemetry.HISTOGRAM_EXPONENTIAL, Telemetry.HISTOGRAM_LINEAR]
|
let kinds = [Telemetry.HISTOGRAM_EXPONENTIAL, Telemetry.HISTOGRAM_LINEAR]
|
||||||
|
@ -160,6 +121,4 @@ function run_test()
|
||||||
test_getHistogramById();
|
test_getHistogramById();
|
||||||
test_getSlowSQL();
|
test_getSlowSQL();
|
||||||
test_privateMode();
|
test_privateMode();
|
||||||
test_loadSave();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче