зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
8910ca900f
|
@ -82,6 +82,29 @@ DocAccessibleChildBase::SerializeTree(Accessible* aRoot,
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
/* static */ void
|
||||
DocAccessibleChildBase::SetMsaaIds(Accessible* aRoot,
|
||||
uint32_t& aMsaaIdIndex,
|
||||
const nsTArray<MsaaMapping>& aNewMsaaIds)
|
||||
{
|
||||
const MsaaMapping& mapping = aNewMsaaIds[aMsaaIdIndex];
|
||||
#if defined(DEBUG)
|
||||
uint64_t id = reinterpret_cast<uint64_t>(aRoot->UniqueID());
|
||||
MOZ_ASSERT(mapping.ID() == id);
|
||||
#endif // defined(DEBUG)
|
||||
static_cast<AccessibleWrap*>(aRoot)->SetID(mapping.MsaaID());
|
||||
++aMsaaIdIndex;
|
||||
if (aRoot->IsOuterDoc()) {
|
||||
// This needs to match the tree traversal in SerializeTree
|
||||
return;
|
||||
}
|
||||
for (uint32_t i = 0, n = aRoot->ChildCount(); i < n; ++i) {
|
||||
SetMsaaIds(aRoot->GetChildAt(i), aMsaaIdIndex, aNewMsaaIds);
|
||||
}
|
||||
}
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
void
|
||||
DocAccessibleChildBase::ShowEvent(AccShowEvent* aShowEvent)
|
||||
{
|
||||
|
@ -91,7 +114,22 @@ DocAccessibleChildBase::ShowEvent(AccShowEvent* aShowEvent)
|
|||
nsTArray<AccessibleData> shownTree;
|
||||
ShowEventData data(parentID, idxInParent, shownTree);
|
||||
SerializeTree(aShowEvent->GetAccessible(), data.NewTree());
|
||||
#if defined(XP_WIN)
|
||||
nsTArray<MsaaMapping> newMsaaIds;
|
||||
SendShowEventInfo(data, &newMsaaIds);
|
||||
// newMsaaIds could be empty if something went wrong in SendShowEvent()
|
||||
if (!newMsaaIds.IsEmpty()) {
|
||||
uint32_t index = 0;
|
||||
SetMsaaIds(aShowEvent->GetAccessible(), index, newMsaaIds);
|
||||
}
|
||||
// NB: On Windows, SendShowEvent attaches the subtree and generates new IDs,
|
||||
// but does *NOT* fire the native event. We need to do that after
|
||||
// we've called SetMsaaIds.
|
||||
SendEvent(reinterpret_cast<uint64_t>(aShowEvent->GetAccessible()->UniqueID()),
|
||||
nsIAccessibleEvent::EVENT_SHOW);
|
||||
#else
|
||||
SendShowEvent(data, aShowEvent->IsFromUserInput());
|
||||
#endif // defined(XP_WIN)
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
|
|
|
@ -60,6 +60,10 @@ public:
|
|||
protected:
|
||||
static uint32_t InterfacesFor(Accessible* aAcc);
|
||||
static void SerializeTree(Accessible* aRoot, nsTArray<AccessibleData>& aTree);
|
||||
#if defined(XP_WIN)
|
||||
static void SetMsaaIds(Accessible* aRoot, uint32_t& aMsaaIdIndex,
|
||||
const nsTArray<MsaaMapping>& aNewMsaaIds);
|
||||
#endif
|
||||
|
||||
DocAccessible* mDoc;
|
||||
};
|
||||
|
|
|
@ -16,8 +16,13 @@ namespace mozilla {
|
|||
namespace a11y {
|
||||
|
||||
bool
|
||||
#if defined(XP_WIN)
|
||||
DocAccessibleParent::RecvShowEventInfo(const ShowEventData& aData,
|
||||
nsTArray<MsaaMapping>* aNewMsaaIds)
|
||||
#else
|
||||
DocAccessibleParent::RecvShowEvent(const ShowEventData& aData,
|
||||
const bool& aFromUser)
|
||||
#endif // defined(XP_WIN)
|
||||
{
|
||||
if (mShutdown)
|
||||
return true;
|
||||
|
@ -44,7 +49,13 @@ DocAccessibleParent::RecvShowEvent(const ShowEventData& aData,
|
|||
return true;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
aNewMsaaIds->SetCapacity(aData.NewTree().Length());
|
||||
uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx,
|
||||
aNewMsaaIds);
|
||||
#else
|
||||
uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx);
|
||||
#endif
|
||||
MOZ_ASSERT(consumed == aData.NewTree().Length());
|
||||
|
||||
// XXX This shouldn't happen, but if we failed to add children then the below
|
||||
|
@ -62,6 +73,9 @@ DocAccessibleParent::RecvShowEvent(const ShowEventData& aData,
|
|||
|
||||
MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
|
||||
|
||||
// NB: On Windows we dispatch the native event via a subsequent call to
|
||||
// RecvEvent().
|
||||
#if !defined(XP_WIN)
|
||||
ProxyAccessible* target = parent->ChildAt(newChildIdx);
|
||||
ProxyShowHideEvent(target, parent, true, aFromUser);
|
||||
|
||||
|
@ -76,6 +90,7 @@ DocAccessibleParent::RecvShowEvent(const ShowEventData& aData,
|
|||
RefPtr<xpcAccEvent> event = new xpcAccEvent(type, xpcAcc, doc, node,
|
||||
aFromUser);
|
||||
nsCoreUtils::DispatchAccEvent(Move(event));
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -83,7 +98,11 @@ DocAccessibleParent::RecvShowEvent(const ShowEventData& aData,
|
|||
uint32_t
|
||||
DocAccessibleParent::AddSubtree(ProxyAccessible* aParent,
|
||||
const nsTArray<a11y::AccessibleData>& aNewTree,
|
||||
uint32_t aIdx, uint32_t aIdxInParent)
|
||||
uint32_t aIdx, uint32_t aIdxInParent
|
||||
#if defined(XP_WIN)
|
||||
, nsTArray<MsaaMapping>* aNewMsaaIds
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (aNewTree.Length() <= aIdx) {
|
||||
NS_ERROR("bad index in serialized tree!");
|
||||
|
@ -124,10 +143,22 @@ DocAccessibleParent::AddSubtree(ProxyAccessible* aParent,
|
|||
mAccessibles.PutEntry(newChild.ID())->mProxy = newProxy;
|
||||
ProxyCreated(newProxy, newChild.Interfaces());
|
||||
|
||||
#if defined(XP_WIN)
|
||||
Accessible* idForAcc = WrapperFor(newProxy);
|
||||
MOZ_ASSERT(idForAcc);
|
||||
uint32_t newMsaaId = AccessibleWrap::GetChildIDFor(idForAcc);
|
||||
MOZ_ASSERT(newMsaaId);
|
||||
aNewMsaaIds->AppendElement(MsaaMapping(newChild.ID(), newMsaaId));
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
uint32_t accessibles = 1;
|
||||
uint32_t kids = newChild.ChildrenCount();
|
||||
for (uint32_t i = 0; i < kids; i++) {
|
||||
uint32_t consumed = AddSubtree(newProxy, aNewTree, aIdx + accessibles, i);
|
||||
uint32_t consumed = AddSubtree(newProxy, aNewTree, aIdx + accessibles, i
|
||||
#if defined(XP_WIN)
|
||||
, aNewMsaaIds
|
||||
#endif
|
||||
);
|
||||
if (!consumed)
|
||||
return 0;
|
||||
|
||||
|
@ -476,7 +507,8 @@ DocAccessibleParent::GetXPCAccessible(ProxyAccessible* aProxy)
|
|||
*/
|
||||
bool
|
||||
DocAccessibleParent::RecvCOMProxy(const IAccessibleHolder& aCOMProxy,
|
||||
IAccessibleHolder* aParentCOMProxy)
|
||||
IAccessibleHolder* aParentCOMProxy,
|
||||
uint32_t* aMsaaID)
|
||||
{
|
||||
RefPtr<IAccessible> ptr(aCOMProxy.Get());
|
||||
SetCOMInterface(ptr);
|
||||
|
@ -488,6 +520,8 @@ DocAccessibleParent::RecvCOMProxy(const IAccessibleHolder& aCOMProxy,
|
|||
}
|
||||
|
||||
aParentCOMProxy->Set(IAccessibleHolder::COMPtrType(rawNative));
|
||||
Accessible* wrapper = WrapperFor(this);
|
||||
*aMsaaID = AccessibleWrap::GetChildIDFor(wrapper);
|
||||
return true;
|
||||
}
|
||||
#endif // defined(XP_WIN)
|
||||
|
|
|
@ -50,8 +50,13 @@ public:
|
|||
virtual bool RecvEvent(const uint64_t& aID, const uint32_t& aType)
|
||||
override;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
virtual bool RecvShowEventInfo(const ShowEventData& aData,
|
||||
nsTArray<MsaaMapping>* aNewMsaaIds) override;
|
||||
#else
|
||||
virtual bool RecvShowEvent(const ShowEventData& aData, const bool& aFromUser)
|
||||
override;
|
||||
#endif // defined(XP_WIN)
|
||||
virtual bool RecvHideEvent(const uint64_t& aRootID, const bool& aFromUser)
|
||||
override;
|
||||
virtual bool RecvStateChangeEvent(const uint64_t& aID,
|
||||
|
@ -144,7 +149,8 @@ public:
|
|||
|
||||
#if defined(XP_WIN)
|
||||
virtual bool RecvCOMProxy(const IAccessibleHolder& aCOMProxy,
|
||||
IAccessibleHolder* aParentCOMProxy) override;
|
||||
IAccessibleHolder* aParentCOMProxy,
|
||||
uint32_t* aMsaaID) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
@ -174,7 +180,11 @@ private:
|
|||
|
||||
uint32_t AddSubtree(ProxyAccessible* aParent,
|
||||
const nsTArray<AccessibleData>& aNewTree, uint32_t aIdx,
|
||||
uint32_t aIdxInParent);
|
||||
uint32_t aIdxInParent
|
||||
#if defined(XP_WIN)
|
||||
, nsTArray<MsaaMapping>* aNewMsaaIds
|
||||
#endif // defined(XP_WIN)
|
||||
);
|
||||
MOZ_MUST_USE bool CheckDocTree() const;
|
||||
xpcAccessibleGeneric* GetXPCAccessible(ProxyAccessible* aProxy);
|
||||
|
||||
|
|
|
@ -34,8 +34,10 @@ void
|
|||
DocAccessibleChild::SendCOMProxy(const IAccessibleHolder& aProxy)
|
||||
{
|
||||
IAccessibleHolder parentProxy;
|
||||
PDocAccessibleChild::SendCOMProxy(aProxy, &parentProxy);
|
||||
uint32_t msaaID = AccessibleWrap::kNoID;
|
||||
PDocAccessibleChild::SendCOMProxy(aProxy, &parentProxy, &msaaID);
|
||||
mParentProxy.reset(parentProxy.Release());
|
||||
mDoc->SetID(msaaID);
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
|
|
|
@ -27,6 +27,12 @@ struct ShowEventData
|
|||
AccessibleData[] NewTree;
|
||||
};
|
||||
|
||||
struct MsaaMapping
|
||||
{
|
||||
uint64_t ID;
|
||||
uint32_t MsaaID;
|
||||
};
|
||||
|
||||
struct Attribute
|
||||
{
|
||||
nsCString Name;
|
||||
|
@ -45,7 +51,7 @@ parent:
|
|||
* event.
|
||||
*/
|
||||
async Event(uint64_t aID, uint32_t type);
|
||||
async ShowEvent(ShowEventData data, bool aFromuser);
|
||||
sync ShowEventInfo(ShowEventData data) returns (MsaaMapping[] aNewMsaaIds);
|
||||
async HideEvent(uint64_t aRootID, bool aFromUser);
|
||||
async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled);
|
||||
async CaretMoveEvent(uint64_t aID, int32_t aOffset);
|
||||
|
@ -63,7 +69,7 @@ parent:
|
|||
// For now we'll add the command to send the proxy here. This might move to
|
||||
// PDocAccessible constructor in PBrowser.
|
||||
sync COMProxy(IAccessibleHolder aDocCOMProxy)
|
||||
returns(IAccessibleHolder aParentCOMProxy);
|
||||
returns(IAccessibleHolder aParentCOMProxy, uint32_t aMsaaID);
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include "Compatibility.h"
|
||||
#include "DocAccessible-inl.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/a11y/DocAccessibleChild.h"
|
||||
#include "mozilla/a11y/DocAccessibleParent.h"
|
||||
#include "EnumVariant.h"
|
||||
#include "nsAccUtils.h"
|
||||
|
@ -69,16 +71,14 @@ static const int32_t kIEnumVariantDisconnected = -1;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
AccessibleWrap::AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
|
||||
Accessible(aContent, aDoc)
|
||||
#ifdef _WIN64
|
||||
, mID(kNoID)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
AccessibleWrap::~AccessibleWrap()
|
||||
{
|
||||
#ifdef _WIN64
|
||||
if (mID != kNoID)
|
||||
if (mID != kNoID && XRE_IsParentProcess())
|
||||
sIDGen.ReleaseID(mID);
|
||||
#endif
|
||||
}
|
||||
|
@ -90,7 +90,6 @@ NS_IMPL_ISUPPORTS_INHERITED0(AccessibleWrap, Accessible)
|
|||
void
|
||||
AccessibleWrap::Shutdown()
|
||||
{
|
||||
#ifdef _WIN64
|
||||
if (mID != kNoID) {
|
||||
auto doc = static_cast<DocAccessibleWrap*>(mDoc);
|
||||
MOZ_ASSERT(doc);
|
||||
|
@ -98,7 +97,6 @@ AccessibleWrap::Shutdown()
|
|||
doc->RemoveID(mID);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Accessible::Shutdown();
|
||||
}
|
||||
|
@ -1147,9 +1145,22 @@ AccessibleWrap::GetNativeInterface(void** aOutAccessible)
|
|||
NS_ADDREF_THIS();
|
||||
}
|
||||
|
||||
void
|
||||
AccessibleWrap::SetID(uint32_t aID)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
mID = aID;
|
||||
DocAccessibleWrap* doc = static_cast<DocAccessibleWrap*>(Document());
|
||||
DebugOnly<AccessibleWrap*> checkAcc = nullptr;
|
||||
MOZ_ASSERT(!(checkAcc = doc->GetAccessibleByID(aID)) ||
|
||||
checkAcc->GetExistingID() == aID);
|
||||
doc->AddID(aID, this);
|
||||
}
|
||||
|
||||
void
|
||||
AccessibleWrap::FireWinEvent(Accessible* aTarget, uint32_t aEventType)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
static_assert(sizeof(gWinEventMap)/sizeof(gWinEventMap[0]) == nsIAccessibleEvent::EVENT_LAST_ENTRY,
|
||||
"MSAA event map skewed");
|
||||
|
||||
|
@ -1246,6 +1257,13 @@ AccessibleWrap::GetChildIDFor(Accessible* aAccessible)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Content should use mID which has been generated by the chrome process.
|
||||
if (XRE_IsContentProcess() && !aAccessible->IsApplication()) {
|
||||
const uint32_t id = static_cast<AccessibleWrap*>(aAccessible)->mID;
|
||||
MOZ_ASSERT(id != kNoID);
|
||||
return id;
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
if (!aAccessible->Document() && !aAccessible->IsProxy())
|
||||
return 0;
|
||||
|
@ -1286,6 +1304,22 @@ AccessibleWrap::GetHWNDFor(Accessible* aAccessible)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
DocAccessible* doc = aAccessible->Document();
|
||||
if (!doc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DocAccessibleChild* ipcDoc = doc->IPCDoc();
|
||||
if (!ipcDoc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto tab = static_cast<dom::TabChild*>(ipcDoc->Manager());
|
||||
MOZ_ASSERT(tab);
|
||||
return reinterpret_cast<HWND>(tab->GetNativeWindowHandle());
|
||||
}
|
||||
|
||||
// Accessibles in child processes are said to have the HWND of the window
|
||||
// their tab is within. Popups are always in the parent process, and so
|
||||
// never proxied, which means this is basically correct.
|
||||
|
@ -1345,7 +1379,6 @@ AccessibleWrap::NativeAccessible(Accessible* aAccessible)
|
|||
return static_cast<IDispatch*>(msaaAccessible);
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
static Accessible*
|
||||
GetAccessibleInSubtree(DocAccessible* aDoc, uint32_t aID)
|
||||
{
|
||||
|
@ -1362,7 +1395,6 @@ GetAccessibleInSubtree(DocAccessible* aDoc, uint32_t aID)
|
|||
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static AccessibleWrap*
|
||||
GetProxiedAccessibleInSubtree(const DocAccessibleParent* aDoc, uint32_t aID)
|
||||
|
@ -1426,7 +1458,9 @@ AccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild)
|
|||
#ifdef _WIN64
|
||||
GetAccessibleInSubtree(document, static_cast<uint32_t>(aVarChild.lVal));
|
||||
#else
|
||||
document->GetAccessibleByUniqueIDInSubtree(uniqueID);
|
||||
XRE_IsContentProcess() ?
|
||||
GetAccessibleInSubtree(document, static_cast<uint32_t>(aVarChild.lVal)) :
|
||||
document->GetAccessibleByUniqueIDInSubtree(uniqueID);
|
||||
#endif
|
||||
|
||||
// If it is a document then just return an accessible.
|
||||
|
|
|
@ -179,17 +179,15 @@ public: // construction, destruction
|
|||
|
||||
static IDispatch* NativeAccessible(Accessible* aAccessible);
|
||||
|
||||
#ifdef _WIN64
|
||||
uint32_t GetExistingID() const { return mID; }
|
||||
static const uint32_t kNoID = 0;
|
||||
#endif
|
||||
// This is only valid to call in content
|
||||
void SetID(uint32_t aID);
|
||||
|
||||
protected:
|
||||
virtual ~AccessibleWrap();
|
||||
|
||||
#ifdef _WIN64
|
||||
uint32_t mID;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Return the wrapper for the document's proxy.
|
||||
|
|
|
@ -48,15 +48,10 @@ STDMETHODIMP
|
|||
DocAccessibleWrap::get_accParent(
|
||||
/* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispParent)
|
||||
{
|
||||
HRESULT hr = DocAccessible::get_accParent(ppdispParent);
|
||||
if (*ppdispParent) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// We might be a top-level document in a content process.
|
||||
DocAccessibleChild* ipcDoc = IPCDoc();
|
||||
if (!ipcDoc) {
|
||||
return S_FALSE;
|
||||
return DocAccessible::get_accParent(ppdispParent);
|
||||
}
|
||||
IAccessible* dispParent = ipcDoc->GetParentIAccessible();
|
||||
if (!dispParent) {
|
||||
|
|
|
@ -40,13 +40,11 @@ public:
|
|||
/**
|
||||
* Manage the mapping from id to Accessible.
|
||||
*/
|
||||
#ifdef _WIN64
|
||||
void AddID(uint32_t aID, AccessibleWrap* aAcc)
|
||||
{ mIDToAccessibleMap.Put(aID, aAcc); }
|
||||
void RemoveID(uint32_t aID) { mIDToAccessibleMap.Remove(aID); }
|
||||
AccessibleWrap* GetAccessibleByID(uint32_t aID) const
|
||||
{ return mIDToAccessibleMap.Get(aID); }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// DocAccessible
|
||||
|
@ -58,9 +56,7 @@ protected:
|
|||
/*
|
||||
* This provides a mapping from 32 bit id to accessible objects.
|
||||
*/
|
||||
#ifdef _WIN64
|
||||
nsDataHashtable<nsUint32HashKey, AccessibleWrap*> mIDToAccessibleMap;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
requestLongerTimeout(2);
|
||||
|
||||
var {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const gHttpTestRoot = "http://example.com/browser/dom/base/test/";
|
||||
|
||||
|
@ -10,7 +11,12 @@ const gHttpTestRoot = "http://example.com/browser/dom/base/test/";
|
|||
* Enable local telemetry recording for the duration of the tests.
|
||||
*/
|
||||
var gOldContentCanRecord = false;
|
||||
var gOldParentCanRecord = false;
|
||||
add_task(function* test_initialize() {
|
||||
let Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
gOldParentCanRecord = Telemetry.canRecordExtended
|
||||
Telemetry.canRecordExtended = true;
|
||||
|
||||
// Because canRecordExtended is a per-process variable, we need to make sure
|
||||
// that all of the pages load in the same content process. Limit the number
|
||||
// of content processes to at most 1 (or 0 if e10s is off entirely).
|
||||
|
@ -74,6 +80,9 @@ add_task(function* () {
|
|||
});
|
||||
|
||||
add_task(function* () {
|
||||
let Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
Telemetry.canRecordExtended = gOldParentCanRecord;
|
||||
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, { oldCanRecord: gOldContentCanRecord }, function (arg) {
|
||||
Cu.import("resource://gre/modules/PromiseUtils.jsm");
|
||||
yield new Promise(resolve => {
|
||||
|
@ -104,22 +113,18 @@ function waitForPageLoad(browser) {
|
|||
});
|
||||
}
|
||||
|
||||
function grabHistogramsFromContent(browser, use_counter_middlefix) {
|
||||
return ContentTask.spawn(browser, { middlefix: use_counter_middlefix }, function* (arg) {
|
||||
let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
function snapshot_histogram(name) {
|
||||
return telemetry.getHistogramById(name).snapshot();
|
||||
}
|
||||
|
||||
let histogram_page_name = "USE_COUNTER2_" + arg.middlefix + "_PAGE";
|
||||
let histogram_document_name = "USE_COUNTER2_" + arg.middlefix + "_DOCUMENT";
|
||||
let histogram_page = snapshot_histogram(histogram_page_name);
|
||||
let histogram_document = snapshot_histogram(histogram_document_name);
|
||||
let histogram_docs = snapshot_histogram("CONTENT_DOCUMENTS_DESTROYED");
|
||||
let histogram_toplevel_docs = snapshot_histogram("TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED");
|
||||
return [histogram_page.sum, histogram_document.sum,
|
||||
histogram_docs.sum, histogram_toplevel_docs.sum];
|
||||
});
|
||||
function grabHistogramsFromContent(use_counter_middlefix, page_before = null) {
|
||||
let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
let suffix = Services.appinfo.browserTabsRemoteAutostart ? "#content" : "";
|
||||
let gather = () => [
|
||||
telemetry.getHistogramById("USE_COUNTER2_" + use_counter_middlefix + "_PAGE" + suffix).snapshot().sum,
|
||||
telemetry.getHistogramById("USE_COUNTER2_" + use_counter_middlefix + "_DOCUMENT" + suffix).snapshot().sum,
|
||||
telemetry.getHistogramById("CONTENT_DOCUMENTS_DESTROYED" + suffix).snapshot().sum,
|
||||
telemetry.getHistogramById("TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED" + suffix).snapshot().sum,
|
||||
];
|
||||
return BrowserTestUtils.waitForCondition(() => {
|
||||
return page_before != telemetry.getHistogramById("USE_COUNTER2_" + use_counter_middlefix + "_PAGE" + suffix).snapshot().sum;
|
||||
}).then(gather, gather);
|
||||
}
|
||||
|
||||
var check_use_counter_iframe = Task.async(function* (file, use_counter_middlefix, check_documents=true) {
|
||||
|
@ -133,7 +138,7 @@ var check_use_counter_iframe = Task.async(function* (file, use_counter_middlefix
|
|||
// interested in.
|
||||
let [histogram_page_before, histogram_document_before,
|
||||
histogram_docs_before, histogram_toplevel_docs_before] =
|
||||
yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
|
||||
yield grabHistogramsFromContent(use_counter_middlefix);
|
||||
|
||||
gBrowser.selectedBrowser.loadURI(gHttpTestRoot + "file_use_counter_outer.html");
|
||||
yield waitForPageLoad(gBrowser.selectedBrowser);
|
||||
|
@ -151,7 +156,7 @@ var check_use_counter_iframe = Task.async(function* (file, use_counter_middlefix
|
|||
event.target.removeEventListener("load", listener, true);
|
||||
|
||||
// We flush the main document first, then the iframe's document to
|
||||
// ensure any propagation that might happen from child->parent should
|
||||
// ensure any propagation that might happen from content->parent should
|
||||
// have already happened when counters are reported to telemetry.
|
||||
wu.forceUseCounterFlush(content.document);
|
||||
wu.forceUseCounterFlush(iframe.contentDocument);
|
||||
|
@ -174,7 +179,7 @@ var check_use_counter_iframe = Task.async(function* (file, use_counter_middlefix
|
|||
// Grab histograms again and compare.
|
||||
let [histogram_page_after, histogram_document_after,
|
||||
histogram_docs_after, histogram_toplevel_docs_after] =
|
||||
yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
|
||||
yield grabHistogramsFromContent(use_counter_middlefix, histogram_page_before);
|
||||
|
||||
is(histogram_page_after, histogram_page_before + 1,
|
||||
"page counts for " + use_counter_middlefix + " after are correct");
|
||||
|
@ -197,7 +202,7 @@ var check_use_counter_img = Task.async(function* (file, use_counter_middlefix) {
|
|||
// interested in.
|
||||
let [histogram_page_before, histogram_document_before,
|
||||
histogram_docs_before, histogram_toplevel_docs_before] =
|
||||
yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
|
||||
yield grabHistogramsFromContent(use_counter_middlefix);
|
||||
|
||||
gBrowser.selectedBrowser.loadURI(gHttpTestRoot + "file_use_counter_outer.html");
|
||||
yield waitForPageLoad(gBrowser.selectedBrowser);
|
||||
|
@ -239,7 +244,7 @@ var check_use_counter_img = Task.async(function* (file, use_counter_middlefix) {
|
|||
// Grab histograms again and compare.
|
||||
let [histogram_page_after, histogram_document_after,
|
||||
histogram_docs_after, histogram_toplevel_docs_after] =
|
||||
yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
|
||||
yield grabHistogramsFromContent(use_counter_middlefix, histogram_page_before);
|
||||
is(histogram_page_after, histogram_page_before + 1,
|
||||
"page counts for " + use_counter_middlefix + " after are correct");
|
||||
is(histogram_document_after, histogram_document_before + 1,
|
||||
|
@ -263,7 +268,7 @@ var check_use_counter_direct = Task.async(function* (file, use_counter_middlefix
|
|||
// interested in.
|
||||
let [histogram_page_before, histogram_document_before,
|
||||
histogram_docs_before, histogram_toplevel_docs_before] =
|
||||
yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
|
||||
yield grabHistogramsFromContent(use_counter_middlefix);
|
||||
|
||||
gBrowser.selectedBrowser.loadURI(gHttpTestRoot + file);
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
|
||||
|
@ -292,7 +297,7 @@ var check_use_counter_direct = Task.async(function* (file, use_counter_middlefix
|
|||
// Grab histograms again and compare.
|
||||
let [histogram_page_after, histogram_document_after,
|
||||
histogram_docs_after, histogram_toplevel_docs_after] =
|
||||
yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
|
||||
yield grabHistogramsFromContent(use_counter_middlefix, histogram_page_before);
|
||||
(xfail ? todo_is : is)(histogram_page_after, histogram_page_before + 1,
|
||||
"page counts for " + use_counter_middlefix + " after are correct");
|
||||
(xfail ? todo_is : is)(histogram_document_after, histogram_document_before + 1,
|
||||
|
|
|
@ -5413,3 +5413,19 @@ ContentParent::ForceTabPaint(TabParent* aTabParent, uint64_t aLayerObserverEpoch
|
|||
}
|
||||
ProcessHangMonitor::ForcePaint(mHangMonitorActor, aTabParent, aLayerObserverEpoch);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvAccumulateChildHistogram(
|
||||
InfallibleTArray<Accumulation>&& aAccumulations)
|
||||
{
|
||||
Telemetry::AccumulateChild(aAccumulations);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvAccumulateChildKeyedHistogram(
|
||||
InfallibleTArray<KeyedAccumulation>&& aAccumulations)
|
||||
{
|
||||
Telemetry::AccumulateChildKeyed(aAccumulations);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1137,6 +1137,10 @@ private:
|
|||
|
||||
virtual bool RecvDeleteGetFilesRequest(const nsID& aID) override;
|
||||
|
||||
virtual bool RecvAccumulateChildHistogram(
|
||||
InfallibleTArray<Accumulation>&& aAccumulations) override;
|
||||
virtual bool RecvAccumulateChildKeyedHistogram(
|
||||
InfallibleTArray<KeyedAccumulation>&& aAccumulations) override;
|
||||
public:
|
||||
void SendGetFilesResponseAndForget(const nsID& aID,
|
||||
const GetFilesResponseResult& aResult);
|
||||
|
|
|
@ -837,6 +837,14 @@ child:
|
|||
*/
|
||||
async Print(uint64_t aOuterWindowID, PrintData aPrintData);
|
||||
|
||||
/**
|
||||
* Update the child with the tab's current top-level native window handle.
|
||||
* This is used by a11y objects who must expose their native window.
|
||||
*
|
||||
* @param aNewHandle The native window handle of the tab's top-level window.
|
||||
*/
|
||||
async UpdateNativeWindowHandle(uintptr_t aNewHandle);
|
||||
|
||||
/*
|
||||
* FIXME: write protocol!
|
||||
|
||||
|
|
|
@ -100,6 +100,8 @@ using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h";
|
|||
using mozilla::DocShellOriginAttributes from "mozilla/ipc/BackgroundUtils.h";
|
||||
using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
|
||||
using struct mozilla::dom::FlyWebPublishOptions from "mozilla/dom/FlyWebPublishOptionsIPCSerializer.h";
|
||||
using mozilla::Telemetry::Accumulation from "mozilla/TelemetryComms.h";
|
||||
using mozilla::Telemetry::KeyedAccumulation from "mozilla/TelemetryComms.h";
|
||||
|
||||
union ChromeRegistryItem
|
||||
{
|
||||
|
@ -1216,6 +1218,12 @@ parent:
|
|||
|
||||
async UnstoreAndBroadcastBlobURLUnregistration(nsCString url);
|
||||
|
||||
/**
|
||||
* Messages for communicating child Telemetry to the parent process
|
||||
*/
|
||||
async AccumulateChildHistogram(Accumulation[] accumulations);
|
||||
async AccumulateChildKeyedHistogram(KeyedAccumulation[] accumulations);
|
||||
|
||||
both:
|
||||
async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
|
||||
Principal aPrincipal, ClonedMessageData aData);
|
||||
|
|
|
@ -549,6 +549,9 @@ TabChild::TabChild(nsIContentChild* aManager,
|
|||
, mDidLoadURLInit(false)
|
||||
, mAPZChild(nullptr)
|
||||
, mLayerObserverEpoch(0)
|
||||
#if defined(XP_WIN) && defined(ACCESSIBILITY)
|
||||
, mNativeWindowHandle(0)
|
||||
#endif
|
||||
{
|
||||
// In the general case having the TabParent tell us if APZ is enabled or not
|
||||
// doesn't really work because the TabParent itself may not have a reference
|
||||
|
@ -2534,6 +2537,17 @@ TabChild::RecvPrint(const uint64_t& aOuterWindowID, const PrintData& aPrintData)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvUpdateNativeWindowHandle(const uintptr_t& aNewHandle)
|
||||
{
|
||||
#if defined(XP_WIN) && defined(ACCESSIBILITY)
|
||||
mNativeWindowHandle = aNewHandle;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvDestroy()
|
||||
{
|
||||
|
|
|
@ -590,6 +590,8 @@ public:
|
|||
virtual bool RecvPrint(const uint64_t& aOuterWindowID,
|
||||
const PrintData& aPrintData) override;
|
||||
|
||||
virtual bool RecvUpdateNativeWindowHandle(const uintptr_t& aNewHandle) override;
|
||||
|
||||
/**
|
||||
* Native widget remoting protocol for use with windowed plugins with e10s.
|
||||
*/
|
||||
|
@ -651,6 +653,10 @@ public:
|
|||
// Request that the docshell be marked as active.
|
||||
void ForcePaint(uint64_t aLayerObserverEpoch);
|
||||
|
||||
#if defined(XP_WIN) && defined(ACCESSIBILITY)
|
||||
uintptr_t GetNativeWindowHandle() const { return mNativeWindowHandle; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual ~TabChild();
|
||||
|
||||
|
@ -789,6 +795,11 @@ private:
|
|||
// The most recently seen layer observer epoch in RecvSetDocShellIsActive.
|
||||
uint64_t mLayerObserverEpoch;
|
||||
|
||||
#if defined(XP_WIN) && defined(ACCESSIBILITY)
|
||||
// The handle associated with the native window that contains this tab
|
||||
uintptr_t mNativeWindowHandle;
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(TabChild);
|
||||
};
|
||||
|
||||
|
|
|
@ -400,6 +400,17 @@ TabParent::SetOwnerElement(Element* aElement)
|
|||
Unused << SendSetUseGlobalHistory(useGlobalHistory);
|
||||
}
|
||||
|
||||
#if defined(XP_WIN) && defined(ACCESSIBILITY)
|
||||
if (!mIsDestroyed) {
|
||||
uintptr_t newWindowHandle = 0;
|
||||
if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
|
||||
newWindowHandle =
|
||||
reinterpret_cast<uintptr_t>(widget->GetNativeData(NS_NATIVE_WINDOW));
|
||||
}
|
||||
Unused << SendUpdateNativeWindowHandle(newWindowHandle);
|
||||
}
|
||||
#endif
|
||||
|
||||
AddWindowListeners();
|
||||
TryCacheDPIAndScale();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 468496-1 will also detect bugs in video drivers.
|
||||
== 468496-1.html 468496-1-ref.html
|
||||
fuzzy-if(winWidget,175,443) == 611498-1.html 611498-ref.html
|
||||
fuzzy(175,443) == 611498-1.html 611498-ref.html
|
||||
skip-if(B2G) fuzzy-if(Android,8,1000) == 709477-1.html 709477-1-ref.html # bug 773482
|
||||
skip-if(!asyncPan) == 1086723.html 1086723-ref.html
|
||||
== 853889-1.html 853889-1-ref.html
|
||||
|
|
|
@ -538,6 +538,10 @@ private:
|
|||
// This affects whether events will be routed through APZ or not.
|
||||
DECL_GFX_PREF(Live, "mousewheel.system_scroll_override_on_root_content.enabled",
|
||||
MouseWheelHasRootScrollDeltaOverride, bool, false);
|
||||
DECL_GFX_PREF(Live, "mousewheel.system_scroll_override_on_root_content.horizontal.factor",
|
||||
MouseWheelRootScrollHorizontalFactor, int32_t, 0);
|
||||
DECL_GFX_PREF(Live, "mousewheel.system_scroll_override_on_root_content.vertical.factor",
|
||||
MouseWheelRootScrollVerticalFactor, int32_t, 0);
|
||||
DECL_GFX_PREF(Live, "mousewheel.transaction.ignoremovedelay",MouseWheelIgnoreMoveDelayMs, int32_t, (int32_t)100);
|
||||
DECL_GFX_PREF(Live, "mousewheel.transaction.timeout", MouseWheelTransactionTimeoutMs, int32_t, (int32_t)1500);
|
||||
|
||||
|
|
|
@ -488,6 +488,7 @@ MessageChannel::MessageChannel(MessageListener *aListener)
|
|||
mSawInterruptOutMsg(false),
|
||||
mIsWaitingForIncoming(false),
|
||||
mAbortOnError(false),
|
||||
mNotifiedChannelDone(false),
|
||||
mFlags(REQUIRE_DEFAULT),
|
||||
mPeerPidSet(false),
|
||||
mPeerPid(-1)
|
||||
|
@ -2081,6 +2082,13 @@ MessageChannel::NotifyMaybeChannelError()
|
|||
// Oops, error! Let the listener know about it.
|
||||
mChannelState = ChannelError;
|
||||
|
||||
// IPDL assumes these notifications do not fire twice, so we do not let
|
||||
// that happen.
|
||||
if (mNotifiedChannelDone) {
|
||||
return;
|
||||
}
|
||||
mNotifiedChannelDone = true;
|
||||
|
||||
// After this, the channel may be deleted. Based on the premise that
|
||||
// mListener owns this channel, any calls back to this class that may
|
||||
// work with mListener should still work on living objects.
|
||||
|
@ -2238,6 +2246,13 @@ MessageChannel::NotifyChannelClosed()
|
|||
|
||||
Clear();
|
||||
|
||||
// IPDL assumes these notifications do not fire twice, so we do not let
|
||||
// that happen.
|
||||
if (mNotifiedChannelDone) {
|
||||
return;
|
||||
}
|
||||
mNotifiedChannelDone = true;
|
||||
|
||||
// OK, the IO thread just closed the channel normally. Let the
|
||||
// listener know about it. After this point the channel may be
|
||||
// deleted.
|
||||
|
|
|
@ -783,6 +783,10 @@ class MessageChannel : HasResultCodes
|
|||
// a channel error occurs?
|
||||
bool mAbortOnError;
|
||||
|
||||
// True if the listener has already been notified of a channel close or
|
||||
// error.
|
||||
bool mNotifiedChannelDone;
|
||||
|
||||
// See SetChannelFlags
|
||||
ChannelFlags mFlags;
|
||||
|
||||
|
|
|
@ -509,6 +509,9 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IsValid() const {
|
||||
return mValid;
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct IPC::ParamTraits<Endpoint<PFooSide>>;
|
||||
|
@ -649,7 +652,10 @@ struct ParamTraits<mozilla::ipc::Endpoint<PFooSide>>
|
|||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(aParam.mValid);
|
||||
IPC::WriteParam(aMsg, aParam.mValid);
|
||||
if (!aParam.mValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::WriteParam(aMsg, static_cast<uint32_t>(aParam.mMode));
|
||||
|
||||
|
@ -668,7 +674,15 @@ struct ParamTraits<mozilla::ipc::Endpoint<PFooSide>>
|
|||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!aResult->mValid);
|
||||
aResult->mValid = true;
|
||||
|
||||
if (!IPC::ReadParam(aMsg, aIter, &aResult->mValid)) {
|
||||
return false;
|
||||
}
|
||||
if (!aResult->mValid) {
|
||||
// Object is empty, but read succeeded.
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t mode, protocolId;
|
||||
if (!IPC::ReadParam(aMsg, aIter, &mode) ||
|
||||
!IPC::ReadParam(aMsg, aIter, &aResult->mTransport) ||
|
||||
|
|
|
@ -2384,7 +2384,10 @@ def _generateCxxUnion(ud):
|
|||
|
||||
# ~Union()
|
||||
dtor = DestructorDefn(DestructorDecl(ud.name))
|
||||
dtor.addstmt(StmtExpr(callMaybeDestroy(tnonevar)))
|
||||
# The void cast prevents Coverity from complaining about missing return
|
||||
# value checks.
|
||||
dtor.addstmt(StmtExpr(ExprCast(callMaybeDestroy(tnonevar), Type.VOID,
|
||||
static=1)))
|
||||
cls.addstmts([ dtor, Whitespace.NL ])
|
||||
|
||||
# type()
|
||||
|
@ -2425,9 +2428,14 @@ def _generateCxxUnion(ud):
|
|||
StmtBreak()
|
||||
])
|
||||
opeqswitch.addcase(CaseLabel(c.enum()), case)
|
||||
opeqswitch.addcase(CaseLabel(tnonevar.name),
|
||||
StmtBlock([ StmtExpr(callMaybeDestroy(rhstypevar)),
|
||||
StmtBreak() ]))
|
||||
opeqswitch.addcase(
|
||||
CaseLabel(tnonevar.name),
|
||||
# The void cast prevents Coverity from complaining about missing return
|
||||
# value checks.
|
||||
StmtBlock([ StmtExpr(ExprCast(callMaybeDestroy(rhstypevar), Type.VOID,
|
||||
static=1)),
|
||||
StmtBreak() ])
|
||||
)
|
||||
opeqswitch.addcase(
|
||||
DefaultLabel(),
|
||||
StmtBlock([ _logicError('unreached'), StmtBreak() ]))
|
||||
|
|
|
@ -6074,6 +6074,8 @@ CodeGenerator::visitCreateArgumentsObject(LCreateArgumentsObject* lir)
|
|||
Register objTemp = ToRegister(lir->temp1());
|
||||
Register cxTemp = ToRegister(lir->temp2());
|
||||
|
||||
masm.Push(callObj);
|
||||
|
||||
// Try to allocate an arguments object. This will leave the reserved
|
||||
// slots uninitialized, so it's important we don't GC until we
|
||||
// initialize these slots in ArgumentsObject::finishForIon.
|
||||
|
@ -6082,7 +6084,7 @@ CodeGenerator::visitCreateArgumentsObject(LCreateArgumentsObject* lir)
|
|||
/* initContents = */ false);
|
||||
|
||||
masm.moveStackPtrTo(temp);
|
||||
masm.addPtr(Imm32(frameSize()), temp);
|
||||
masm.addPtr(Imm32(masm.framePushed()), temp);
|
||||
|
||||
masm.setupUnalignedABICall(cxTemp);
|
||||
masm.loadJSContext(cxTemp);
|
||||
|
@ -6092,10 +6094,14 @@ CodeGenerator::visitCreateArgumentsObject(LCreateArgumentsObject* lir)
|
|||
masm.passABIArg(objTemp);
|
||||
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ArgumentsObject::finishForIon));
|
||||
masm.branchTestPtr(Assembler::Zero, ReturnReg, ReturnReg, masm.exceptionLabel());
|
||||
masm.branchTestPtr(Assembler::Zero, ReturnReg, ReturnReg, &failure);
|
||||
|
||||
// Discard saved callObj on the stack.
|
||||
masm.addToStackPtr(Imm32(sizeof(uintptr_t)));
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&failure);
|
||||
masm.Pop(callObj);
|
||||
}
|
||||
|
||||
masm.moveStackPtrTo(temp);
|
||||
|
|
|
@ -383,7 +383,9 @@ ArgumentsObject::finishForIon(JSContext* cx, jit::JitFrameLayout* frame,
|
|||
ArgumentsData* data =
|
||||
reinterpret_cast<ArgumentsData*>(AllocateObjectBuffer<uint8_t>(cx, obj, numBytes));
|
||||
if (!data) {
|
||||
// Make the object safe for GC.
|
||||
// Make the object safe for GC. Don't report OOM, the slow path will
|
||||
// retry the allocation.
|
||||
cx->recoverFromOutOfMemory();
|
||||
obj->initFixedSlot(DATA_SLOT, PrivateValue(nullptr));
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -49,17 +49,20 @@ jobs:
|
|||
when:
|
||||
files-changed:
|
||||
- build/**
|
||||
- config/**
|
||||
- configure.py
|
||||
- dom/bindings/**
|
||||
- intl/icu/**
|
||||
- js/moz.configure
|
||||
- layout/tools/reftest/reftest/**
|
||||
- Makefile.in
|
||||
- media/webrtc/trunk/tools/gyp/**
|
||||
- memory/**
|
||||
- mfbt/**
|
||||
- modules/fdlibm/**
|
||||
- modules/zlib/src/**
|
||||
- mozglue/**
|
||||
- moz.build
|
||||
- moz.configure
|
||||
- nsprpub/**
|
||||
- python/**
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
[iframe-allow-fullscreen.html.ini]
|
||||
type: testharness
|
||||
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1282024
|
||||
prefs: [full-screen-api.unprefix.enabled:true]
|
||||
|
|
|
@ -14,6 +14,7 @@ import sys
|
|||
import tempfile
|
||||
import unittest
|
||||
|
||||
from buildconfig import substs
|
||||
from StringIO import StringIO
|
||||
from mozlog import structured
|
||||
from mozbuild.base import MozbuildObject
|
||||
|
@ -27,7 +28,6 @@ mozinfo.find_and_update_from_json()
|
|||
objdir = build_obj.topobjdir.encode("utf-8")
|
||||
|
||||
if mozinfo.isMac:
|
||||
from buildconfig import substs
|
||||
xpcshellBin = os.path.join(objdir, "dist", substs['MOZ_MACBUNDLE_NAME'], "Contents", "MacOS", "xpcshell")
|
||||
else:
|
||||
xpcshellBin = os.path.join(objdir, "dist", "bin", "xpcshell")
|
||||
|
@ -858,7 +858,9 @@ add_test({
|
|||
|
||||
self.assertTestResult(False)
|
||||
self.assertInLog(TEST_FAIL_STRING)
|
||||
self.assertInLog("test_simple_uncaught_rejection.js:3:3")
|
||||
if not substs.get('RELEASE_BUILD'):
|
||||
# async stacks are currently not enabled in release builds.
|
||||
self.assertInLog("test_simple_uncaught_rejection.js:3:3")
|
||||
self.assertInLog("Test rejection.")
|
||||
self.assertEquals(1, self.x.testCount)
|
||||
self.assertEquals(0, self.x.passCount)
|
||||
|
|
|
@ -2348,6 +2348,13 @@ TelemetryImpl::ClearScalars()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TelemetryImpl::FlushBatchedChildTelemetry()
|
||||
{
|
||||
TelemetryHistogram::IPCTimerFired(nullptr, nullptr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
size_t
|
||||
TelemetryImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
{
|
||||
|
@ -2793,6 +2800,18 @@ AccumulateTimeDelta(ID aHistogram, TimeStamp start, TimeStamp end)
|
|||
static_cast<uint32_t>((end - start).ToMilliseconds()));
|
||||
}
|
||||
|
||||
void
|
||||
AccumulateChild(const nsTArray<Accumulation>& aAccumulations)
|
||||
{
|
||||
TelemetryHistogram::AccumulateChild(aAccumulations);
|
||||
}
|
||||
|
||||
void
|
||||
AccumulateChildKeyed(const nsTArray<KeyedAccumulation>& aAccumulations)
|
||||
{
|
||||
TelemetryHistogram::AccumulateChildKeyed(aAccumulations);
|
||||
}
|
||||
|
||||
void
|
||||
ClearHistogram(ID aId)
|
||||
{
|
||||
|
|
|
@ -33,6 +33,9 @@ namespace HangMonitor {
|
|||
} // namespace HangMonitor
|
||||
namespace Telemetry {
|
||||
|
||||
struct Accumulation;
|
||||
struct KeyedAccumulation;
|
||||
|
||||
enum TimerResolution {
|
||||
Millisecond,
|
||||
Microsecond
|
||||
|
@ -125,6 +128,20 @@ void AccumulateCategorical(ID id, const nsCString& label);
|
|||
*/
|
||||
void AccumulateTimeDelta(ID id, TimeStamp start, TimeStamp end = TimeStamp::Now());
|
||||
|
||||
/**
|
||||
* Accumulate child data into child histograms
|
||||
*
|
||||
* @param aAccumulations - accumulation actions to perform
|
||||
*/
|
||||
void AccumulateChild(const nsTArray<Accumulation>& aAccumulations);
|
||||
|
||||
/**
|
||||
* Accumulate child data into child keyed histograms
|
||||
*
|
||||
* @param aAccumulations - accumulation actions to perform
|
||||
*/
|
||||
void AccumulateChildKeyed(const nsTArray<KeyedAccumulation>& aAccumulations);
|
||||
|
||||
/**
|
||||
* This clears the data for a histogram in TelemetryHistogramEnums.h.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
*/
|
||||
|
||||
#ifndef Telemetry_Comms_h__
|
||||
#define Telemetry_Comms_h__
|
||||
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace Telemetry {
|
||||
|
||||
enum ID : uint32_t;
|
||||
|
||||
struct Accumulation
|
||||
{
|
||||
mozilla::Telemetry::ID mId;
|
||||
uint32_t mSample;
|
||||
};
|
||||
|
||||
struct KeyedAccumulation
|
||||
{
|
||||
mozilla::Telemetry::ID mId;
|
||||
uint32_t mSample;
|
||||
nsCString mKey;
|
||||
};
|
||||
|
||||
} // namespace Telemetry
|
||||
} // namespace mozilla
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
struct
|
||||
ParamTraits<mozilla::Telemetry::Accumulation>
|
||||
{
|
||||
typedef mozilla::Telemetry::Accumulation paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
aMsg->WriteUInt32(aParam.mId);
|
||||
WriteParam(aMsg, aParam.mSample);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
if (!aMsg->ReadUInt32(aIter, reinterpret_cast<uint32_t*>(&(aResult->mId))) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mSample))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct
|
||||
ParamTraits<mozilla::Telemetry::KeyedAccumulation>
|
||||
{
|
||||
typedef mozilla::Telemetry::KeyedAccumulation paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
aMsg->WriteUInt32(aParam.mId);
|
||||
WriteParam(aMsg, aParam.mSample);
|
||||
WriteParam(aMsg, aParam.mKey);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
if (!aMsg->ReadUInt32(aIter, reinterpret_cast<uint32_t*>(&(aResult->mId))) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mSample)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mKey))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // Telemetry_Comms_h__
|
|
@ -14,9 +14,13 @@
|
|||
#include "nsClassHashtable.h"
|
||||
#include "nsITelemetry.h"
|
||||
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/StartupTimeline.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "TelemetryCommon.h"
|
||||
#include "TelemetryHistogram.h"
|
||||
|
@ -31,6 +35,9 @@ using base::FlagHistogram;
|
|||
using base::LinearHistogram;
|
||||
using mozilla::StaticMutex;
|
||||
using mozilla::StaticMutexAutoLock;
|
||||
using mozilla::StaticAutoPtr;
|
||||
using mozilla::Telemetry::Accumulation;
|
||||
using mozilla::Telemetry::KeyedAccumulation;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -92,6 +99,7 @@ using mozilla::StaticMutexAutoLock;
|
|||
#define EXPIRED_ID "__expired__"
|
||||
#define SUBSESSION_HISTOGRAM_PREFIX "sub#"
|
||||
#define KEYED_HISTOGRAM_NAME_SEPARATOR "#"
|
||||
#define CHILD_HISTOGRAM_SUFFIX "#content"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -185,6 +193,13 @@ AddonMapType gAddonMap;
|
|||
// The singleton StatisticsRecorder object for this process.
|
||||
base::StatisticsRecorder* gStatisticsRecorder = nullptr;
|
||||
|
||||
// For batching and sending child process accumulations to the parent
|
||||
nsITimer* gIPCTimer = nullptr;
|
||||
mozilla::Atomic<bool, mozilla::Relaxed> gIPCTimerArmed(false);
|
||||
mozilla::Atomic<bool, mozilla::Relaxed> gIPCTimerArming(false);
|
||||
StaticAutoPtr<nsTArray<Accumulation>> gAccumulations;
|
||||
StaticAutoPtr<nsTArray<KeyedAccumulation>> gKeyedAccumulations;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
@ -204,6 +219,17 @@ const mozilla::Telemetry::ID kRecordingInitiallyDisabledIDs[] = {
|
|||
mozilla::Telemetry::TELEMETRY_TEST_KEYED_COUNT_INIT_NO_RECORD
|
||||
};
|
||||
|
||||
// Sending each remote accumulation immediately places undue strain on the
|
||||
// IPC subsystem. Batch the remote accumulations for a period of time before
|
||||
// sending them all at once. This value was chosen as a balance between data
|
||||
// timeliness and performance (see bug 1218576)
|
||||
const uint32_t kBatchTimeoutMs = 2000;
|
||||
|
||||
// To stop growing unbounded in memory while waiting for kBatchTimeoutMs to
|
||||
// drain the g*Accumulations arrays, request an immediate flush if the arrays
|
||||
// manage to reach this high water mark of elements.
|
||||
const size_t kAccumulationsArrayHighWaterMark = 5 * 1024;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
@ -311,6 +337,16 @@ HistogramInfo::label_id(const char* label, uint32_t* labelId) const
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool
|
||||
StringEndsWith(const std::string& name, const std::string& suffix)
|
||||
{
|
||||
if (name.size() < suffix.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return name.compare(name.size() - suffix.size(), suffix.size(), suffix) == 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
@ -395,6 +431,18 @@ internal_HistogramGet(const char *name, const char *expiration,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
CharPtrEntryType*
|
||||
internal_GetHistogramMapEntry(const char* name)
|
||||
{
|
||||
nsDependentCString histogramName(name);
|
||||
NS_NAMED_LITERAL_CSTRING(suffix, CHILD_HISTOGRAM_SUFFIX);
|
||||
if (!StringEndsWith(histogramName, suffix)) {
|
||||
return gHistogramMap.GetEntry(name);
|
||||
}
|
||||
auto root = Substring(histogramName, 0, histogramName.Length() - suffix.Length());
|
||||
return gHistogramMap.GetEntry(PromiseFlatCString(root).get());
|
||||
}
|
||||
|
||||
nsresult
|
||||
internal_GetHistogramEnumId(const char *name, mozilla::Telemetry::ID *id)
|
||||
{
|
||||
|
@ -402,7 +450,7 @@ internal_GetHistogramEnumId(const char *name, mozilla::Telemetry::ID *id)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
CharPtrEntryType *entry = gHistogramMap.GetEntry(name);
|
||||
CharPtrEntryType *entry = internal_GetHistogramMapEntry(name);
|
||||
if (!entry) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
@ -412,10 +460,12 @@ internal_GetHistogramEnumId(const char *name, mozilla::Telemetry::ID *id)
|
|||
|
||||
// O(1) histogram lookup by numeric id
|
||||
nsresult
|
||||
internal_GetHistogramByEnumId(mozilla::Telemetry::ID id, Histogram **ret)
|
||||
internal_GetHistogramByEnumId(mozilla::Telemetry::ID id, Histogram **ret,
|
||||
bool child = false)
|
||||
{
|
||||
static Histogram* knownHistograms[mozilla::Telemetry::HistogramCount] = {0};
|
||||
Histogram *h = knownHistograms[id];
|
||||
static Histogram* knownChildHistograms[mozilla::Telemetry::HistogramCount] = {0};
|
||||
Histogram *h = child ? knownChildHistograms[id] : knownHistograms[id];
|
||||
if (h) {
|
||||
*ret = h;
|
||||
return NS_OK;
|
||||
|
@ -426,8 +476,15 @@ internal_GetHistogramByEnumId(mozilla::Telemetry::ID id, Histogram **ret)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = internal_HistogramGet(p.id(), p.expiration(), p.histogramType,
|
||||
p.min, p.max, p.bucketCount, true, &h);
|
||||
nsCString histogramName;
|
||||
histogramName.Append(p.id());
|
||||
if (child) {
|
||||
histogramName.AppendLiteral(CHILD_HISTOGRAM_SUFFIX);
|
||||
}
|
||||
|
||||
nsresult rv = internal_HistogramGet(histogramName.get(), p.expiration(),
|
||||
p.histogramType, p.min, p.max,
|
||||
p.bucketCount, true, &h);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
|
@ -447,7 +504,11 @@ internal_GetHistogramByEnumId(mozilla::Telemetry::ID id, Histogram **ret)
|
|||
}
|
||||
#endif
|
||||
|
||||
*ret = knownHistograms[id] = h;
|
||||
if (child) {
|
||||
*ret = knownChildHistograms[id] = h;
|
||||
} else {
|
||||
*ret = knownHistograms[id] = h;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -461,7 +522,9 @@ internal_GetHistogramByName(const nsACString &name, Histogram **ret)
|
|||
return rv;
|
||||
}
|
||||
|
||||
rv = internal_GetHistogramByEnumId(id, ret);
|
||||
bool isChild = StringEndsWith(name,
|
||||
NS_LITERAL_CSTRING(CHILD_HISTOGRAM_SUFFIX));
|
||||
rv = internal_GetHistogramByEnumId(id, ret, isChild);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
|
@ -517,6 +580,7 @@ internal_CloneHistogram(const nsACString& newName,
|
|||
}
|
||||
|
||||
#if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
Histogram*
|
||||
internal_GetSubsessionHistogram(Histogram& existing)
|
||||
{
|
||||
|
@ -527,9 +591,14 @@ internal_GetSubsessionHistogram(Histogram& existing)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool isChild = StringEndsWith(existing.histogram_name(),
|
||||
CHILD_HISTOGRAM_SUFFIX);
|
||||
|
||||
static Histogram* subsession[mozilla::Telemetry::HistogramCount] = {};
|
||||
if (subsession[id]) {
|
||||
return subsession[id];
|
||||
static Histogram* subsessionChild[mozilla::Telemetry::HistogramCount] = {};
|
||||
Histogram* cached = isChild ? subsessionChild[id] : subsession[id];
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(prefix, SUBSESSION_HISTOGRAM_PREFIX);
|
||||
|
@ -539,10 +608,15 @@ internal_GetSubsessionHistogram(Histogram& existing)
|
|||
}
|
||||
|
||||
nsCString subsessionName(prefix);
|
||||
subsessionName.Append(existingName);
|
||||
subsessionName.Append(existing.histogram_name().c_str());
|
||||
|
||||
subsession[id] = internal_CloneHistogram(subsessionName, id, existing);
|
||||
return subsession[id];
|
||||
Histogram* clone = internal_CloneHistogram(subsessionName, id, existing);
|
||||
if (isChild) {
|
||||
subsessionChild[id] = clone;
|
||||
} else {
|
||||
subsession[id] = clone;
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -591,26 +665,13 @@ internal_HistogramAdd(Histogram& histogram, int32_t value)
|
|||
return internal_HistogramAdd(histogram, value, dataset);
|
||||
}
|
||||
|
||||
nsresult
|
||||
internal_HistogramAddCategorical(mozilla::Telemetry::ID id, const nsCString& label)
|
||||
{
|
||||
uint32_t labelId = 0;
|
||||
if (NS_FAILED(gHistograms[id].label_id(label.get(), &labelId))) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
Histogram* h = nullptr;
|
||||
nsresult rv = internal_GetHistogramByEnumId(id, &h);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return internal_HistogramAdd(*h, labelId);
|
||||
}
|
||||
|
||||
void
|
||||
internal_HistogramClear(Histogram& aHistogram, bool onlySubsession)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return;
|
||||
}
|
||||
if (!onlySubsession) {
|
||||
aHistogram.Clear();
|
||||
}
|
||||
|
@ -806,6 +867,8 @@ public:
|
|||
nsresult Add(const nsCString& key, uint32_t aSample);
|
||||
void Clear(bool subsession);
|
||||
|
||||
nsresult GetEnumId(mozilla::Telemetry::ID& id);
|
||||
|
||||
private:
|
||||
typedef nsBaseHashtableET<nsCStringHashKey, Histogram*> KeyedHistogramEntry;
|
||||
typedef AutoHashtable<KeyedHistogramEntry> KeyedHistogramMapType;
|
||||
|
@ -948,6 +1011,10 @@ KeyedHistogram::Add(const nsCString& key, uint32_t sample)
|
|||
void
|
||||
KeyedHistogram::Clear(bool onlySubsession)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return;
|
||||
}
|
||||
#if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
|
||||
for (auto iter = mSubsessionMap.Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.Get()->mData->Clear();
|
||||
|
@ -1035,6 +1102,12 @@ KeyedHistogram::GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
KeyedHistogram::GetEnumId(mozilla::Telemetry::ID& id)
|
||||
{
|
||||
return internal_GetHistogramEnumId(mName.get(), &id);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
@ -1060,6 +1133,319 @@ internal_GetKeyedHistogramById(const nsACString &name)
|
|||
} // namespace
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE: functions related to addon histograms
|
||||
|
||||
namespace {
|
||||
|
||||
// Compute the name to pass into Histogram for the addon histogram
|
||||
// 'name' from the addon 'id'. We can't use 'name' directly because it
|
||||
// might conflict with other histograms in other addons or even with our
|
||||
// own.
|
||||
void
|
||||
internal_AddonHistogramName(const nsACString &id, const nsACString &name,
|
||||
nsACString &ret)
|
||||
{
|
||||
ret.Append(id);
|
||||
ret.Append(':');
|
||||
ret.Append(name);
|
||||
}
|
||||
|
||||
bool
|
||||
internal_CreateHistogramForAddon(const nsACString &name,
|
||||
AddonHistogramInfo &info)
|
||||
{
|
||||
Histogram *h;
|
||||
nsresult rv = internal_HistogramGet(PromiseFlatCString(name).get(), "never",
|
||||
info.histogramType, info.min, info.max,
|
||||
info.bucketCount, true, &h);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
// Don't let this histogram be reported via the normal means
|
||||
// (e.g. Telemetry.registeredHistograms); we'll make it available in
|
||||
// other ways.
|
||||
h->ClearFlags(Histogram::kUmaTargetedHistogramFlag);
|
||||
info.h = h;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
internal_AddonHistogramReflector(AddonHistogramEntryType *entry,
|
||||
JSContext *cx, JS::Handle<JSObject*> obj)
|
||||
{
|
||||
AddonHistogramInfo &info = entry->mData;
|
||||
|
||||
// Never even accessed the histogram.
|
||||
if (!info.h) {
|
||||
// Have to force creation of HISTOGRAM_FLAG histograms.
|
||||
if (info.histogramType != nsITelemetry::HISTOGRAM_FLAG)
|
||||
return true;
|
||||
|
||||
if (!internal_CreateHistogramForAddon(entry->GetKey(), info)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (internal_IsEmpty(info.h)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> snapshot(cx, JS_NewPlainObject(cx));
|
||||
if (!snapshot) {
|
||||
// Just consider this to be skippable.
|
||||
return true;
|
||||
}
|
||||
switch (internal_ReflectHistogramSnapshot(cx, snapshot, info.h)) {
|
||||
case REFLECT_FAILURE:
|
||||
case REFLECT_CORRUPT:
|
||||
return false;
|
||||
case REFLECT_OK:
|
||||
const nsACString &histogramName = entry->GetKey();
|
||||
if (!JS_DefineProperty(cx, obj, PromiseFlatCString(histogramName).get(),
|
||||
snapshot, JSPROP_ENUMERATE)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
internal_AddonReflector(AddonEntryType *entry, JSContext *cx,
|
||||
JS::Handle<JSObject*> obj)
|
||||
{
|
||||
const nsACString &addonId = entry->GetKey();
|
||||
JS::Rooted<JSObject*> subobj(cx, JS_NewPlainObject(cx));
|
||||
if (!subobj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AddonHistogramMapType *map = entry->mData;
|
||||
if (!(map->ReflectIntoJS(internal_AddonHistogramReflector, cx, subobj)
|
||||
&& JS_DefineProperty(cx, obj, PromiseFlatCString(addonId).get(),
|
||||
subobj, JSPROP_ENUMERATE))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE: thread-unsafe helpers for the external interface
|
||||
|
||||
// This is a StaticMutex rather than a plain Mutex (1) so that
|
||||
// it gets initialised in a thread-safe manner the first time
|
||||
// it is used, and (2) because it is never de-initialised, and
|
||||
// a normal Mutex would show up as a leak in BloatView. StaticMutex
|
||||
// also has the "OffTheBooks" property, so it won't show as a leak
|
||||
// in BloatView.
|
||||
static StaticMutex gTelemetryHistogramMutex;
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
internal_SetHistogramRecordingEnabled(mozilla::Telemetry::ID aID, bool aEnabled)
|
||||
{
|
||||
if (!internal_IsHistogramEnumId(aID)) {
|
||||
MOZ_ASSERT(false, "Telemetry::SetHistogramRecordingEnabled(...) must be used with an enum id");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gHistograms[aID].keyed) {
|
||||
const nsDependentCString id(gHistograms[aID].id());
|
||||
KeyedHistogram* keyed = internal_GetKeyedHistogramById(id);
|
||||
if (keyed) {
|
||||
keyed->SetRecordingEnabled(aEnabled);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Histogram *h;
|
||||
nsresult rv = internal_GetHistogramByEnumId(aID, &h);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
h->SetRecordingEnabled(aEnabled);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "Telemetry::SetHistogramRecordingEnabled(...) id not found");
|
||||
}
|
||||
|
||||
void internal_armIPCTimerMainThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
gIPCTimerArming = false;
|
||||
if (gIPCTimerArmed) {
|
||||
return;
|
||||
}
|
||||
if (!gIPCTimer) {
|
||||
CallCreateInstance(NS_TIMER_CONTRACTID, &gIPCTimer);
|
||||
}
|
||||
if (gIPCTimer) {
|
||||
gIPCTimer->InitWithFuncCallback(TelemetryHistogram::IPCTimerFired,
|
||||
nullptr, kBatchTimeoutMs,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
gIPCTimerArmed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void internal_armIPCTimer()
|
||||
{
|
||||
if (gIPCTimerArmed || gIPCTimerArming) {
|
||||
return;
|
||||
}
|
||||
gIPCTimerArming = true;
|
||||
if (NS_IsMainThread()) {
|
||||
internal_armIPCTimerMainThread();
|
||||
} else {
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void {
|
||||
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
||||
internal_armIPCTimerMainThread();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
internal_RemoteAccumulate(mozilla::Telemetry::ID aId, uint32_t aSample)
|
||||
{
|
||||
if (XRE_IsParentProcess()) {
|
||||
return false;
|
||||
}
|
||||
if (!gAccumulations) {
|
||||
gAccumulations = new nsTArray<Accumulation>();
|
||||
}
|
||||
if (gAccumulations->Length() == kAccumulationsArrayHighWaterMark) {
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void {
|
||||
TelemetryHistogram::IPCTimerFired(nullptr, nullptr);
|
||||
}));
|
||||
}
|
||||
gAccumulations->AppendElement(Accumulation{aId, aSample});
|
||||
internal_armIPCTimer();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
internal_RemoteAccumulate(mozilla::Telemetry::ID aId,
|
||||
const nsCString& aKey, uint32_t aSample)
|
||||
{
|
||||
if (XRE_IsParentProcess()) {
|
||||
return false;
|
||||
}
|
||||
if (!gKeyedAccumulations) {
|
||||
gKeyedAccumulations = new nsTArray<KeyedAccumulation>();
|
||||
}
|
||||
if (gKeyedAccumulations->Length() == kAccumulationsArrayHighWaterMark) {
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void {
|
||||
TelemetryHistogram::IPCTimerFired(nullptr, nullptr);
|
||||
}));
|
||||
}
|
||||
gKeyedAccumulations->AppendElement(KeyedAccumulation{aId, aSample, aKey});
|
||||
internal_armIPCTimer();
|
||||
return true;
|
||||
}
|
||||
|
||||
void internal_Accumulate(mozilla::Telemetry::ID aHistogram, uint32_t aSample)
|
||||
{
|
||||
bool isValid = internal_IsHistogramEnumId(aHistogram);
|
||||
MOZ_ASSERT(isValid, "Accumulation using invalid id");
|
||||
if (!internal_CanRecordBase() || !isValid ||
|
||||
internal_RemoteAccumulate(aHistogram, aSample)) {
|
||||
return;
|
||||
}
|
||||
Histogram *h;
|
||||
nsresult rv = internal_GetHistogramByEnumId(aHistogram, &h);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
internal_HistogramAdd(*h, aSample, gHistograms[aHistogram].dataset);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
internal_Accumulate(mozilla::Telemetry::ID aID,
|
||||
const nsCString& aKey, uint32_t aSample)
|
||||
{
|
||||
bool isValid = internal_IsHistogramEnumId(aID);
|
||||
MOZ_ASSERT(isValid, "Child keyed telemetry accumulation using invalid id");
|
||||
if (!gInitDone || !internal_CanRecordBase() || !isValid ||
|
||||
internal_RemoteAccumulate(aID, aKey, aSample)) {
|
||||
return;
|
||||
}
|
||||
const HistogramInfo& th = gHistograms[aID];
|
||||
KeyedHistogram* keyed
|
||||
= internal_GetKeyedHistogramById(nsDependentCString(th.id()));
|
||||
MOZ_ASSERT(keyed);
|
||||
keyed->Add(aKey, aSample);
|
||||
}
|
||||
|
||||
void
|
||||
internal_Accumulate(Histogram& aHistogram, uint32_t aSample)
|
||||
{
|
||||
if (XRE_IsParentProcess()) {
|
||||
internal_HistogramAdd(aHistogram, aSample);
|
||||
return;
|
||||
}
|
||||
|
||||
mozilla::Telemetry::ID id;
|
||||
nsresult rv = internal_GetHistogramEnumId(aHistogram.histogram_name().c_str(), &id);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
internal_RemoteAccumulate(id, aSample);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
internal_Accumulate(KeyedHistogram& aKeyed,
|
||||
const nsCString& aKey, uint32_t aSample)
|
||||
{
|
||||
if (XRE_IsParentProcess()) {
|
||||
aKeyed.Add(aKey, aSample);
|
||||
return;
|
||||
}
|
||||
|
||||
mozilla::Telemetry::ID id;
|
||||
if (NS_SUCCEEDED(aKeyed.GetEnumId(id))) {
|
||||
internal_RemoteAccumulate(id, aKey, aSample);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
internal_AccumulateChild(mozilla::Telemetry::ID aId, uint32_t aSample)
|
||||
{
|
||||
if (!internal_CanRecordBase()) {
|
||||
return;
|
||||
}
|
||||
Histogram* h;
|
||||
nsresult rv = internal_GetHistogramByEnumId(aId, &h, true);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
internal_HistogramAdd(*h, aSample, gHistograms[aId].dataset);
|
||||
} else {
|
||||
NS_WARNING("NS_FAILED GetHistogramByEnumId for CHILD");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
internal_AccumulateChildKeyed(mozilla::Telemetry::ID aId,
|
||||
const nsCString& aKey, uint32_t aSample)
|
||||
{
|
||||
if (!gInitDone || !internal_CanRecordBase()) {
|
||||
return;
|
||||
}
|
||||
const HistogramInfo& th = gHistograms[aId];
|
||||
nsCString id;
|
||||
id.Append(th.id());
|
||||
id.AppendLiteral(CHILD_HISTOGRAM_SUFFIX);
|
||||
KeyedHistogram* keyed = internal_GetKeyedHistogramById(id);
|
||||
MOZ_ASSERT(keyed);
|
||||
keyed->Add(aKey, aSample);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
@ -1102,52 +1488,47 @@ internal_JSHistogram_Add(JSContext *cx, unsigned argc, JS::Value *vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
// If we don't have an argument for the count histogram, assume an increment of 1.
|
||||
// Otherwise, make sure to run some sanity checks on the argument.
|
||||
if ((type == base::CountHistogram::COUNT_HISTOGRAM) && (args.length() == 0)) {
|
||||
internal_HistogramAdd(*h, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// For categorical histograms we allow passing a string argument that specifies the label.
|
||||
uint32_t value = 0;
|
||||
mozilla::Telemetry::ID id;
|
||||
if (type == base::LinearHistogram::LINEAR_HISTOGRAM &&
|
||||
if ((type == base::CountHistogram::COUNT_HISTOGRAM) && (args.length() == 0)) {
|
||||
// If we don't have an argument for the count histogram, assume an increment of 1.
|
||||
// Otherwise, make sure to run some sanity checks on the argument.
|
||||
value = 1;
|
||||
} else if (type == base::LinearHistogram::LINEAR_HISTOGRAM &&
|
||||
(args.length() > 0) && args[0].isString() &&
|
||||
NS_SUCCEEDED(internal_GetHistogramEnumId(h->histogram_name().c_str(), &id)) &&
|
||||
gHistograms[id].histogramType == nsITelemetry::HISTOGRAM_CATEGORICAL) {
|
||||
// For categorical histograms we allow passing a string argument that specifies the label.
|
||||
nsAutoJSString label;
|
||||
if (!label.init(cx, args[0])) {
|
||||
JS_ReportError(cx, "Invalid string parameter");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = internal_HistogramAddCategorical(id, NS_ConvertUTF16toUTF8(label));
|
||||
nsresult rv = gHistograms[id].label_id(NS_ConvertUTF16toUTF8(label).get(), &value);
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ReportError(cx, "Unknown label for categorical histogram");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// All other accumulations expect one numerical argument.
|
||||
if (!args.length()) {
|
||||
JS_ReportError(cx, "Expected one argument");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!(args[0].isNumber() || args[0].isBoolean())) {
|
||||
JS_ReportError(cx, "Not a number");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!JS::ToUint32(cx, args[0], &value)) {
|
||||
JS_ReportError(cx, "Failed to convert argument");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// All other accumulations expect one numerical argument.
|
||||
int32_t value = 0;
|
||||
if (!args.length()) {
|
||||
JS_ReportError(cx, "Expected one argument");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(args[0].isNumber() || args[0].isBoolean())) {
|
||||
JS_ReportError(cx, "Not a number");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!JS::ToInt32(cx, args[0], &value)) {
|
||||
JS_ReportError(cx, "Failed to convert argument");
|
||||
return false;
|
||||
}
|
||||
|
||||
internal_HistogramAdd(*h, value);
|
||||
internal_Accumulate(*h, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1395,7 +1776,7 @@ internal_JSKeyedHistogram_Add(JSContext *cx, unsigned argc, JS::Value *vp)
|
|||
}
|
||||
}
|
||||
|
||||
keyed->Add(NS_ConvertUTF16toUTF8(key), value);
|
||||
internal_Accumulate(*keyed, NS_ConvertUTF16toUTF8(key), value);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1545,184 +1926,11 @@ internal_WrapAndReturnKeyedHistogram(KeyedHistogram *h, JSContext *cx,
|
|||
} // namespace
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE: functions related to addon histograms
|
||||
|
||||
namespace {
|
||||
|
||||
// Compute the name to pass into Histogram for the addon histogram
|
||||
// 'name' from the addon 'id'. We can't use 'name' directly because it
|
||||
// might conflict with other histograms in other addons or even with our
|
||||
// own.
|
||||
void
|
||||
internal_AddonHistogramName(const nsACString &id, const nsACString &name,
|
||||
nsACString &ret)
|
||||
{
|
||||
ret.Append(id);
|
||||
ret.Append(':');
|
||||
ret.Append(name);
|
||||
}
|
||||
|
||||
bool
|
||||
internal_CreateHistogramForAddon(const nsACString &name,
|
||||
AddonHistogramInfo &info)
|
||||
{
|
||||
Histogram *h;
|
||||
nsresult rv = internal_HistogramGet(PromiseFlatCString(name).get(), "never",
|
||||
info.histogramType, info.min, info.max,
|
||||
info.bucketCount, true, &h);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
// Don't let this histogram be reported via the normal means
|
||||
// (e.g. Telemetry.registeredHistograms); we'll make it available in
|
||||
// other ways.
|
||||
h->ClearFlags(Histogram::kUmaTargetedHistogramFlag);
|
||||
info.h = h;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
internal_AddonHistogramReflector(AddonHistogramEntryType *entry,
|
||||
JSContext *cx, JS::Handle<JSObject*> obj)
|
||||
{
|
||||
AddonHistogramInfo &info = entry->mData;
|
||||
|
||||
// Never even accessed the histogram.
|
||||
if (!info.h) {
|
||||
// Have to force creation of HISTOGRAM_FLAG histograms.
|
||||
if (info.histogramType != nsITelemetry::HISTOGRAM_FLAG)
|
||||
return true;
|
||||
|
||||
if (!internal_CreateHistogramForAddon(entry->GetKey(), info)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (internal_IsEmpty(info.h)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> snapshot(cx, JS_NewPlainObject(cx));
|
||||
if (!snapshot) {
|
||||
// Just consider this to be skippable.
|
||||
return true;
|
||||
}
|
||||
switch (internal_ReflectHistogramSnapshot(cx, snapshot, info.h)) {
|
||||
case REFLECT_FAILURE:
|
||||
case REFLECT_CORRUPT:
|
||||
return false;
|
||||
case REFLECT_OK:
|
||||
const nsACString &histogramName = entry->GetKey();
|
||||
if (!JS_DefineProperty(cx, obj, PromiseFlatCString(histogramName).get(),
|
||||
snapshot, JSPROP_ENUMERATE)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
internal_AddonReflector(AddonEntryType *entry, JSContext *cx,
|
||||
JS::Handle<JSObject*> obj)
|
||||
{
|
||||
const nsACString &addonId = entry->GetKey();
|
||||
JS::Rooted<JSObject*> subobj(cx, JS_NewPlainObject(cx));
|
||||
if (!subobj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AddonHistogramMapType *map = entry->mData;
|
||||
if (!(map->ReflectIntoJS(internal_AddonHistogramReflector, cx, subobj)
|
||||
&& JS_DefineProperty(cx, obj, PromiseFlatCString(addonId).get(),
|
||||
subobj, JSPROP_ENUMERATE))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE: thread-unsafe helpers for the external interface
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
internal_SetHistogramRecordingEnabled(mozilla::Telemetry::ID aID, bool aEnabled)
|
||||
{
|
||||
if (!internal_IsHistogramEnumId(aID)) {
|
||||
MOZ_ASSERT(false, "Telemetry::SetHistogramRecordingEnabled(...) must be used with an enum id");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gHistograms[aID].keyed) {
|
||||
const nsDependentCString id(gHistograms[aID].id());
|
||||
KeyedHistogram* keyed = internal_GetKeyedHistogramById(id);
|
||||
if (keyed) {
|
||||
keyed->SetRecordingEnabled(aEnabled);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Histogram *h;
|
||||
nsresult rv = internal_GetHistogramByEnumId(aID, &h);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
h->SetRecordingEnabled(aEnabled);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "Telemetry::SetHistogramRecordingEnabled(...) id not found");
|
||||
}
|
||||
|
||||
void internal_Accumulate(mozilla::Telemetry::ID aHistogram, uint32_t aSample)
|
||||
{
|
||||
if (!internal_CanRecordBase()) {
|
||||
return;
|
||||
}
|
||||
Histogram *h;
|
||||
nsresult rv = internal_GetHistogramByEnumId(aHistogram, &h);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
internal_HistogramAdd(*h, aSample, gHistograms[aHistogram].dataset);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
internal_Accumulate(mozilla::Telemetry::ID aID,
|
||||
const nsCString& aKey, uint32_t aSample)
|
||||
{
|
||||
if (!gInitDone || !internal_CanRecordBase()) {
|
||||
return;
|
||||
}
|
||||
const HistogramInfo& th = gHistograms[aID];
|
||||
KeyedHistogram* keyed
|
||||
= internal_GetKeyedHistogramById(nsDependentCString(th.id()));
|
||||
MOZ_ASSERT(keyed);
|
||||
keyed->Add(aKey, aSample);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// EXTERNALLY VISIBLE FUNCTIONS in namespace TelemetryHistogram::
|
||||
|
||||
// This is a StaticMutex rather than a plain Mutex (1) so that
|
||||
// it gets initialised in a thread-safe manner the first time
|
||||
// it is used, and (2) because it is never de-initialised, and
|
||||
// a normal Mutex would show up as a leak in BloatView. StaticMutex
|
||||
// also has the "OffTheBooks" property, so it won't show as a leak
|
||||
// in BloatView.
|
||||
static StaticMutex gTelemetryHistogramMutex;
|
||||
|
||||
// All of these functions are actually in namespace TelemetryHistogram::,
|
||||
// but the ::TelemetryHistogram prefix is given explicitly. This is
|
||||
// because it is critical to see which calls from these functions are
|
||||
|
@ -1786,6 +1994,16 @@ void TelemetryHistogram::InitializeGlobalState(bool canRecordBase,
|
|||
const nsDependentCString expiration(h.expiration());
|
||||
gKeyedHistograms.Put(id, new KeyedHistogram(id, expiration, h.histogramType,
|
||||
h.min, h.max, h.bucketCount, h.dataset));
|
||||
if (XRE_IsParentProcess()) {
|
||||
// We must create registered child keyed histograms as well or else the
|
||||
// same code in TelemetrySession.jsm that fails without parent keyed
|
||||
// histograms will fail without child keyed histograms.
|
||||
nsCString childId(id);
|
||||
childId.AppendLiteral(CHILD_HISTOGRAM_SUFFIX);
|
||||
gKeyedHistograms.Put(childId,
|
||||
new KeyedHistogram(id, expiration, h.histogramType,
|
||||
h.min, h.max, h.bucketCount, h.dataset));
|
||||
}
|
||||
}
|
||||
|
||||
// Some Telemetry histograms depend on the value of C++ constants and hardcode
|
||||
|
@ -1816,6 +2034,11 @@ void TelemetryHistogram::DeInitializeGlobalState()
|
|||
gHistogramMap.Clear();
|
||||
gKeyedHistograms.Clear();
|
||||
gAddonMap.Clear();
|
||||
gAccumulations = nullptr;
|
||||
gKeyedAccumulations = nullptr;
|
||||
if (gIPCTimer) {
|
||||
NS_RELEASE(gIPCTimer);
|
||||
}
|
||||
gInitDone = false;
|
||||
}
|
||||
|
||||
|
@ -1921,12 +2144,7 @@ TelemetryHistogram::Accumulate(const char* name, uint32_t sample)
|
|||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Histogram *h;
|
||||
rv = internal_GetHistogramByEnumId(id, &h);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
internal_HistogramAdd(*h, sample, gHistograms[id].dataset);
|
||||
}
|
||||
internal_Accumulate(id, sample);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1949,7 +2167,52 @@ TelemetryHistogram::AccumulateCategorical(mozilla::Telemetry::ID aId,
|
|||
const nsCString& label)
|
||||
{
|
||||
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
||||
internal_HistogramAddCategorical(aId, label);
|
||||
if (!internal_CanRecordBase()) {
|
||||
return;
|
||||
}
|
||||
uint32_t labelId = 0;
|
||||
if (NS_FAILED(gHistograms[aId].label_id(label.get(), &labelId))) {
|
||||
return;
|
||||
}
|
||||
internal_Accumulate(aId, labelId);
|
||||
}
|
||||
|
||||
void
|
||||
TelemetryHistogram::AccumulateChild(const nsTArray<Accumulation>& aAccumulations)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
||||
if (!internal_CanRecordBase()) {
|
||||
return;
|
||||
}
|
||||
for (uint32_t i = 0; i < aAccumulations.Length(); ++i) {
|
||||
bool isValid = internal_IsHistogramEnumId(aAccumulations[i].mId);
|
||||
MOZ_ASSERT(isValid);
|
||||
if (!isValid) {
|
||||
continue;
|
||||
}
|
||||
internal_AccumulateChild(aAccumulations[i].mId, aAccumulations[i].mSample);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TelemetryHistogram::AccumulateChildKeyed(const nsTArray<KeyedAccumulation>& aAccumulations)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
||||
if (!internal_CanRecordBase()) {
|
||||
return;
|
||||
}
|
||||
for (uint32_t i = 0; i < aAccumulations.Length(); ++i) {
|
||||
bool isValid = internal_IsHistogramEnumId(aAccumulations[i].mId);
|
||||
MOZ_ASSERT(isValid);
|
||||
if (!isValid) {
|
||||
continue;
|
||||
}
|
||||
internal_AccumulateChildKeyed(aAccumulations[i].mId,
|
||||
aAccumulations[i].mKey,
|
||||
aAccumulations[i].mSample);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2058,6 +2321,8 @@ TelemetryHistogram::CreateHistogramSnapshots(JSContext *cx,
|
|||
mozilla::DebugOnly<nsresult> rv
|
||||
= internal_GetHistogramByEnumId(mozilla::Telemetry::ID(i), &h);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
rv = internal_GetHistogramByEnumId(mozilla::Telemetry::ID(i), &h, true);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2321,3 +2586,43 @@ TelemetryHistogram::GetHistogramSizesofIncludingThis(mozilla::MallocSizeOf
|
|||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// This method takes the lock only to double-buffer the batched telemetry.
|
||||
// It releases the lock before calling out to IPC code which can (and does)
|
||||
// Accumulate (which would deadlock)
|
||||
//
|
||||
// To ensure we don't loop IPCTimerFired->AccumulateChild->arm timer, we don't
|
||||
// unset gIPCTimerArmed until the IPC completes
|
||||
//
|
||||
// This function must be called on the main thread, otherwise IPC will fail.
|
||||
void
|
||||
TelemetryHistogram::IPCTimerFired(nsITimer* aTimer, void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsTArray<Accumulation> accumulationsToSend;
|
||||
nsTArray<KeyedAccumulation> keyedAccumulationsToSend;
|
||||
{
|
||||
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
||||
if (gAccumulations) {
|
||||
accumulationsToSend.SwapElements(*gAccumulations);
|
||||
}
|
||||
if (gKeyedAccumulations) {
|
||||
keyedAccumulationsToSend.SwapElements(*gKeyedAccumulations);
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::dom::ContentChild* contentChild = mozilla::dom::ContentChild::GetSingleton();
|
||||
mozilla::Unused << NS_WARN_IF(!contentChild);
|
||||
if (contentChild) {
|
||||
if (accumulationsToSend.Length()) {
|
||||
mozilla::Unused <<
|
||||
NS_WARN_IF(!contentChild->SendAccumulateChildHistogram(accumulationsToSend));
|
||||
}
|
||||
if (keyedAccumulationsToSend.Length()) {
|
||||
mozilla::Unused <<
|
||||
NS_WARN_IF(!contentChild->SendAccumulateChildKeyedHistogram(keyedAccumulationsToSend));
|
||||
}
|
||||
}
|
||||
|
||||
gIPCTimerArmed = false;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include "mozilla/TelemetryHistogramEnums.h"
|
||||
|
||||
#include "mozilla/TelemetryComms.h"
|
||||
|
||||
// This module is internal to Telemetry. It encapsulates Telemetry's
|
||||
// histogram accumulation and storage logic. It should only be used by
|
||||
// Telemetry.cpp. These functions should not be used anywhere else.
|
||||
|
@ -42,6 +44,9 @@ void Accumulate(const char* name, const nsCString& key, uint32_t sample);
|
|||
|
||||
void AccumulateCategorical(mozilla::Telemetry::ID aId, const nsCString& aLabel);
|
||||
|
||||
void AccumulateChild(const nsTArray<mozilla::Telemetry::Accumulation>& aAccumulations);
|
||||
void AccumulateChildKeyed(const nsTArray<mozilla::Telemetry::KeyedAccumulation>& aAccumulations);
|
||||
|
||||
void
|
||||
ClearHistogram(mozilla::Telemetry::ID aId);
|
||||
|
||||
|
@ -96,6 +101,8 @@ GetMapShallowSizesOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);
|
|||
size_t
|
||||
GetHistogramSizesofIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
|
||||
|
||||
void
|
||||
IPCTimerFired(nsITimer* aTimer, void* aClosure);
|
||||
} // namespace TelemetryHistogram
|
||||
|
||||
#endif // TelemetryHistogram_h__
|
||||
|
|
|
@ -41,6 +41,11 @@ const REASON_TEST_PING = "test-ping";
|
|||
const REASON_ENVIRONMENT_CHANGE = "environment-change";
|
||||
const REASON_SHUTDOWN = "shutdown";
|
||||
|
||||
const HISTOGRAM_SUFFIXES = {
|
||||
PARENT: "",
|
||||
CONTENT: "#content",
|
||||
}
|
||||
|
||||
const ENVIRONMENT_CHANGE_LISTENER = "TelemetrySession::onEnvironmentChange";
|
||||
|
||||
const MS_IN_ONE_HOUR = 60 * 60 * 1000;
|
||||
|
@ -57,7 +62,6 @@ const PREF_UNIFIED = PREF_BRANCH + "unified";
|
|||
|
||||
|
||||
const MESSAGE_TELEMETRY_PAYLOAD = "Telemetry:Payload";
|
||||
const MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD = "Telemetry:GetChildPayload";
|
||||
const MESSAGE_TELEMETRY_THREAD_HANGS = "Telemetry:ChildThreadHangs";
|
||||
const MESSAGE_TELEMETRY_GET_CHILD_THREAD_HANGS = "Telemetry:GetChildThreadHangs";
|
||||
const MESSAGE_TELEMETRY_USS = "Telemetry:USS";
|
||||
|
@ -540,13 +544,6 @@ this.TelemetrySession = Object.freeze({
|
|||
getPayload: function(reason, clearSubsession = false) {
|
||||
return Impl.getPayload(reason, clearSubsession);
|
||||
},
|
||||
/**
|
||||
* Asks the content processes to send their payloads.
|
||||
* @returns Object
|
||||
*/
|
||||
requestChildPayloads: function() {
|
||||
return Impl.requestChildPayloads();
|
||||
},
|
||||
/**
|
||||
* Returns a promise that resolves to an array of thread hang stats from content processes, one entry per process.
|
||||
* The structure of each entry is identical to that of "threadHangStats" in nsITelemetry.
|
||||
|
@ -884,23 +881,28 @@ var Impl = {
|
|||
},
|
||||
|
||||
getHistograms: function getHistograms(subsession, clearSubsession) {
|
||||
this._log.trace("getHistograms - subsession: " + subsession + ", clearSubsession: " + clearSubsession);
|
||||
this._log.trace("getHistograms - subsession: " + subsession +
|
||||
", clearSubsession: " + clearSubsession);
|
||||
|
||||
let registered =
|
||||
Telemetry.registeredHistograms(this.getDatasetType(), []);
|
||||
if (this._testing == false) {
|
||||
// Omit telemetry test histograms outside of tests.
|
||||
registered = registered.filter(n => !n.startsWith("TELEMETRY_TEST_"));
|
||||
}
|
||||
registered = registered.concat(registered.map(n => "STARTUP_" + n));
|
||||
|
||||
let hls = subsession ? Telemetry.snapshotSubsessionHistograms(clearSubsession)
|
||||
: Telemetry.histogramSnapshots;
|
||||
let ret = {};
|
||||
|
||||
for (let name of registered) {
|
||||
for (let n of [name, "STARTUP_" + name]) {
|
||||
if (n in hls) {
|
||||
// Omit telemetry test histograms outside of tests.
|
||||
if (n.startsWith('TELEMETRY_TEST_') && this._testing == false) {
|
||||
this._log.trace("getHistograms - Skipping test histogram: " + n);
|
||||
} else {
|
||||
ret[n] = this.packHistogram(hls[n]);
|
||||
for (let suffix of Object.values(HISTOGRAM_SUFFIXES)) {
|
||||
if (name + suffix in hls) {
|
||||
if (!(suffix in ret)) {
|
||||
ret[suffix] = {};
|
||||
}
|
||||
ret[suffix][name] = this.packHistogram(hls[name + suffix]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -928,36 +930,41 @@ var Impl = {
|
|||
},
|
||||
|
||||
getKeyedHistograms: function(subsession, clearSubsession) {
|
||||
this._log.trace("getKeyedHistograms - subsession: " + subsession + ", clearSubsession: " + clearSubsession);
|
||||
this._log.trace("getKeyedHistograms - subsession: " + subsession +
|
||||
", clearSubsession: " + clearSubsession);
|
||||
|
||||
let registered =
|
||||
Telemetry.registeredKeyedHistograms(this.getDatasetType(), []);
|
||||
if (this._testing == false) {
|
||||
// Omit telemetry test histograms outside of tests.
|
||||
registered = registered.filter(id => !id.startsWith("TELEMETRY_TEST_"));
|
||||
}
|
||||
let ret = {};
|
||||
|
||||
for (let id of registered) {
|
||||
// Omit telemetry test histograms outside of tests.
|
||||
if (id.startsWith('TELEMETRY_TEST_') && this._testing == false) {
|
||||
this._log.trace("getKeyedHistograms - Skipping test histogram: " + id);
|
||||
continue;
|
||||
}
|
||||
let keyed = Telemetry.getKeyedHistogramById(id);
|
||||
let snapshot = null;
|
||||
if (subsession) {
|
||||
snapshot = clearSubsession ? keyed.snapshotSubsessionAndClear()
|
||||
: keyed.subsessionSnapshot();
|
||||
} else {
|
||||
snapshot = keyed.snapshot();
|
||||
}
|
||||
for (let suffix of Object.values(HISTOGRAM_SUFFIXES)) {
|
||||
let keyed = Telemetry.getKeyedHistogramById(id + suffix);
|
||||
let snapshot = null;
|
||||
if (subsession) {
|
||||
snapshot = clearSubsession ? keyed.snapshotSubsessionAndClear()
|
||||
: keyed.subsessionSnapshot();
|
||||
} else {
|
||||
snapshot = keyed.snapshot();
|
||||
}
|
||||
|
||||
let keys = Object.keys(snapshot);
|
||||
if (keys.length == 0) {
|
||||
// Skip empty keyed histogram.
|
||||
continue;
|
||||
}
|
||||
let keys = Object.keys(snapshot);
|
||||
if (keys.length == 0) {
|
||||
// Skip empty keyed histogram.
|
||||
continue;
|
||||
}
|
||||
|
||||
ret[id] = {};
|
||||
for (let key of keys) {
|
||||
ret[id][key] = this.packHistogram(snapshot[key]);
|
||||
if (!(suffix in ret)) {
|
||||
ret[suffix] = {};
|
||||
}
|
||||
ret[suffix][id] = {};
|
||||
for (let key of keys) {
|
||||
ret[suffix][id][key] = this.packHistogram(snapshot[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1243,12 +1250,12 @@ var Impl = {
|
|||
|
||||
// This allows wrapping data retrieval calls in a try-catch block so that
|
||||
// failures don't break the rest of the ping assembly.
|
||||
const protect = (fn) => {
|
||||
const protect = (fn, defaultReturn = null) => {
|
||||
try {
|
||||
return fn();
|
||||
} catch (ex) {
|
||||
this._log.error("assemblePayloadWithMeasurements - caught exception", ex);
|
||||
return null;
|
||||
return defaultReturn;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1256,8 +1263,6 @@ var Impl = {
|
|||
let payloadObj = {
|
||||
ver: PAYLOAD_VERSION,
|
||||
simpleMeasurements: simpleMeasurements,
|
||||
histograms: protect(() => this.getHistograms(isSubsession, clearSubsession)),
|
||||
keyedHistograms: protect(() => this.getKeyedHistograms(isSubsession, clearSubsession)),
|
||||
};
|
||||
|
||||
// Add extended set measurements common to chrome & content processes
|
||||
|
@ -1272,14 +1277,21 @@ var Impl = {
|
|||
return payloadObj;
|
||||
}
|
||||
|
||||
// Set the scalars for the parent process.
|
||||
// Additional payload for chrome process.
|
||||
let histograms = protect(() => this.getHistograms(isSubsession, clearSubsession), {});
|
||||
let keyedHistograms = protect(() => this.getKeyedHistograms(isSubsession, clearSubsession), {});
|
||||
payloadObj.histograms = histograms[HISTOGRAM_SUFFIXES.PARENT] || {};
|
||||
payloadObj.keyedHistograms = keyedHistograms[HISTOGRAM_SUFFIXES.PARENT] || {};
|
||||
payloadObj.processes = {
|
||||
parent: {
|
||||
scalars: protect(() => this.getScalars(isSubsession, clearSubsession)),
|
||||
}
|
||||
},
|
||||
content: {
|
||||
histograms: histograms[HISTOGRAM_SUFFIXES.CONTENT],
|
||||
keyedHistograms: keyedHistograms[HISTOGRAM_SUFFIXES.CONTENT],
|
||||
},
|
||||
};
|
||||
|
||||
// Additional payload for chrome process.
|
||||
payloadObj.info = info;
|
||||
|
||||
// Add extended set measurements for chrome process.
|
||||
|
@ -1521,7 +1533,6 @@ var Impl = {
|
|||
}
|
||||
|
||||
Services.obs.addObserver(this, "content-child-shutdown", false);
|
||||
cpml.addMessageListener(MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD, this);
|
||||
cpml.addMessageListener(MESSAGE_TELEMETRY_GET_CHILD_THREAD_HANGS, this);
|
||||
cpml.addMessageListener(MESSAGE_TELEMETRY_GET_CHILD_USS, this);
|
||||
|
||||
|
@ -1559,14 +1570,6 @@ var Impl = {
|
|||
let source = message.data.childUUID;
|
||||
delete message.data.childUUID;
|
||||
|
||||
for (let child of this._childTelemetry) {
|
||||
if (child.source === source) {
|
||||
// Update existing telemetry data.
|
||||
child.payload = message.data;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Did not find existing child in this._childTelemetry.
|
||||
this._childTelemetry.push({
|
||||
source: source,
|
||||
payload: message.data,
|
||||
|
@ -1579,12 +1582,6 @@ var Impl = {
|
|||
|
||||
break;
|
||||
}
|
||||
case MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD:
|
||||
{
|
||||
// In child process, send the requested Telemetry payload
|
||||
this.sendContentProcessPing("saved-session");
|
||||
break;
|
||||
}
|
||||
case MESSAGE_TELEMETRY_THREAD_HANGS:
|
||||
{
|
||||
// Accumulate child thread hang stats from this child
|
||||
|
@ -1764,11 +1761,6 @@ var Impl = {
|
|||
return this.getSessionPayload(reason, clearSubsession);
|
||||
},
|
||||
|
||||
requestChildPayloads: function() {
|
||||
this._log.trace("requestChildPayloads");
|
||||
ppmm.broadcastAsyncMessage(MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD, {});
|
||||
},
|
||||
|
||||
getChildThreadHangs: function getChildThreadHangs() {
|
||||
return new Promise((resolve) => {
|
||||
// Return immediately if there are no child processes to get stats from
|
||||
|
@ -1846,7 +1838,7 @@ var Impl = {
|
|||
// content-child-shutdown is only registered for content processes.
|
||||
Services.obs.removeObserver(this, "content-child-shutdown");
|
||||
this.uninstall();
|
||||
|
||||
Telemetry.flushBatchedChildTelemetry();
|
||||
this.sendContentProcessPing(REASON_SAVED_SESSION);
|
||||
break;
|
||||
case TOPIC_CYCLE_COLLECTOR_BEGIN:
|
||||
|
|
|
@ -19,6 +19,7 @@ EXPORTS.mozilla += [
|
|||
'!TelemetryScalarEnums.h',
|
||||
'ProcessedStack.h',
|
||||
'Telemetry.h',
|
||||
'TelemetryComms.h',
|
||||
'ThreadHangStats.h',
|
||||
]
|
||||
|
||||
|
|
|
@ -396,4 +396,10 @@ interface nsITelemetry : nsISupports
|
|||
* Resets all the stored scalars. This is intended to be only used in tests.
|
||||
*/
|
||||
void clearScalars();
|
||||
|
||||
/**
|
||||
* Immediately sends any Telemetry batched on this process to the parent
|
||||
* process. This is intended only to be used on process shutdown.
|
||||
*/
|
||||
void flushBatchedChildTelemetry();
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Cu.import("resource://gre/modules/TelemetryController.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetrySession.jsm", this);
|
||||
Cu.import("resource://gre/modules/PromiseUtils.jsm", this);
|
||||
Cu.import("resource://testing-common/ContentTaskUtils.jsm", this);
|
||||
|
||||
const MESSAGE_TELEMETRY_PAYLOAD = "Telemetry:Payload";
|
||||
const MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD = "Telemetry:GetChildPayload";
|
||||
|
@ -19,6 +20,9 @@ function run_child_test() {
|
|||
let countHist = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT");
|
||||
countHist.add();
|
||||
countHist.add();
|
||||
let categHist = Telemetry.getHistogramById("TELEMETRY_TEST_CATEGORICAL");
|
||||
categHist.add("Label2");
|
||||
categHist.add("Label3");
|
||||
|
||||
let flagKeyed = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_FLAG");
|
||||
flagKeyed.add("a", 1);
|
||||
|
@ -27,20 +31,19 @@ function run_child_test() {
|
|||
countKeyed.add("a");
|
||||
countKeyed.add("b");
|
||||
countKeyed.add("b");
|
||||
|
||||
// Check payload values.
|
||||
const payload = TelemetrySession.getPayload("test-ping");
|
||||
check_histogram_values(payload);
|
||||
}
|
||||
|
||||
function check_histogram_values(payload) {
|
||||
const hs = payload.histograms;
|
||||
Assert.ok("TELEMETRY_TEST_COUNT" in hs, "Should have count test histogram.");
|
||||
Assert.ok("TELEMETRY_TEST_FLAG" in hs, "Should have flag test histogram.");
|
||||
Assert.ok("TELEMETRY_TEST_CATEGORICAL" in hs, "Should have categorical test histogram.");
|
||||
Assert.equal(hs["TELEMETRY_TEST_COUNT"].sum, 2,
|
||||
"Count test histogram should have the right value.");
|
||||
Assert.equal(hs["TELEMETRY_TEST_FLAG"].sum, 1,
|
||||
"Flag test histogram should have the right value.");
|
||||
Assert.equal(hs["TELEMETRY_TEST_CATEGORICAL"].sum, 3,
|
||||
"Categorical test histogram should have the right sum.");
|
||||
|
||||
const kh = payload.keyedHistograms;
|
||||
Assert.ok("TELEMETRY_TEST_KEYED_COUNT" in kh, "Should have keyed count test histogram.");
|
||||
|
@ -61,8 +64,6 @@ add_task(function*() {
|
|||
run_child_test();
|
||||
dump("... done with child test\n");
|
||||
do_send_remote_message(MESSAGE_CHILD_TEST_DONE);
|
||||
dump("... waiting for child payload collection\n");
|
||||
yield do_await_remote_message(MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -80,20 +81,20 @@ add_task(function*() {
|
|||
let childPromise = run_test_in_child("test_ChildHistograms.js");
|
||||
yield do_await_remote_message(MESSAGE_CHILD_TEST_DONE);
|
||||
|
||||
// Gather payload from child.
|
||||
dump("... requesting child payloads\n");
|
||||
let promiseMessage = do_await_remote_message(MESSAGE_TELEMETRY_PAYLOAD);
|
||||
TelemetrySession.requestChildPayloads();
|
||||
yield promiseMessage;
|
||||
dump("... received child payload\n");
|
||||
|
||||
// Check child payload.
|
||||
yield ContentTaskUtils.waitForCondition(() => {
|
||||
let payload = TelemetrySession.getPayload("test-ping");
|
||||
return payload &&
|
||||
"processes" in payload &&
|
||||
"content" in payload.processes &&
|
||||
"histograms" in payload.processes.content &&
|
||||
"TELEMETRY_TEST_COUNT" in payload.processes.content.histograms;
|
||||
});
|
||||
const payload = TelemetrySession.getPayload("test-ping");
|
||||
Assert.ok("childPayloads" in payload, "Should have child payloads.");
|
||||
Assert.equal(payload.childPayloads.length, 1, "Should have received one child payload so far.");
|
||||
Assert.ok("histograms" in payload.childPayloads[0], "Child payload should have histograms.");
|
||||
Assert.ok("keyedHistograms" in payload.childPayloads[0], "Child payload should have keyed histograms.");
|
||||
check_histogram_values(payload.childPayloads[0]);
|
||||
Assert.ok("processes" in payload, "Should have processes section");
|
||||
Assert.ok("content" in payload.processes, "Should have child process section");
|
||||
Assert.ok("histograms" in payload.processes.content, "Child process section should have histograms.");
|
||||
Assert.ok("keyedHistograms" in payload.processes.content, "Child process section should have keyed histograms.");
|
||||
check_histogram_values(payload.processes.content);
|
||||
|
||||
do_test_finished();
|
||||
});
|
||||
|
|
|
@ -229,6 +229,14 @@ body[dir="rtl"] .copy-node {
|
|||
display: inline;
|
||||
}
|
||||
|
||||
.processes-ui {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.has-data.expanded .processes-ui {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.filter-blocked {
|
||||
display: none;
|
||||
}
|
||||
|
@ -257,3 +265,7 @@ body[dir="rtl"] .copy-node {
|
|||
font-size: larger;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.process-picker {
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
|
|
|
@ -306,6 +306,10 @@ var PingPicker = {
|
|||
.addEventListener("click", () => this._movePingIndex(1), false);
|
||||
document.getElementById("choose-payload")
|
||||
.addEventListener("change", () => displayPingData(gPingData), false);
|
||||
document.getElementById("histograms-processes")
|
||||
.addEventListener("change", () => displayPingData(gPingData), false);
|
||||
document.getElementById("keyed-histograms-processes")
|
||||
.addEventListener("change", () => displayPingData(gPingData), false);
|
||||
},
|
||||
|
||||
onPingSourceChanged: function() {
|
||||
|
@ -1782,6 +1786,33 @@ function sortStartupMilestones(aSimpleMeasurements) {
|
|||
return result;
|
||||
}
|
||||
|
||||
function renderProcessList(ping, selectEl) {
|
||||
removeAllChildNodes(selectEl);
|
||||
let option = document.createElement("option");
|
||||
option.appendChild(document.createTextNode("parent"));
|
||||
option.setAttribute("value", "");
|
||||
option.selected = true;
|
||||
selectEl.appendChild(option);
|
||||
|
||||
if (!("processes" in ping.payload)) {
|
||||
selectEl.disabled = true;
|
||||
return;
|
||||
}
|
||||
selectEl.disabled = false;
|
||||
|
||||
for (let process of Object.keys(ping.payload.processes)) {
|
||||
// TODO: parent hgrams are on root payload, not in payload.processes.parent
|
||||
// When/If that gets moved, you'll need to remove this:
|
||||
if (process === "parent") {
|
||||
continue;
|
||||
}
|
||||
option = document.createElement("option");
|
||||
option.appendChild(document.createTextNode(process));
|
||||
option.setAttribute("value", process);
|
||||
selectEl.appendChild(option);
|
||||
}
|
||||
}
|
||||
|
||||
function renderPayloadList(ping) {
|
||||
// Rebuild the payload select with options:
|
||||
// Parent Payload (selected)
|
||||
|
@ -1850,9 +1881,11 @@ function displayPingData(ping, updatePayloadList = false) {
|
|||
const keysHeader = bundle.GetStringFromName("keysHeader");
|
||||
const valuesHeader = bundle.GetStringFromName("valuesHeader");
|
||||
|
||||
// Update the payload list
|
||||
// Update the payload list and process lists
|
||||
if (updatePayloadList) {
|
||||
renderPayloadList(ping);
|
||||
renderProcessList(ping, document.getElementById("histograms-processes"));
|
||||
renderProcessList(ping, document.getElementById("keyed-histograms-processes"));
|
||||
}
|
||||
|
||||
// Show general data.
|
||||
|
@ -1929,8 +1962,18 @@ function displayPingData(ping, updatePayloadList = false) {
|
|||
removeAllChildNodes(hgramDiv);
|
||||
|
||||
let histograms = payload.histograms;
|
||||
|
||||
let hgramsSelect = document.getElementById("histograms-processes");
|
||||
let hgramsOption = hgramsSelect.selectedOptions.item(0);
|
||||
let hgramsProcess = hgramsOption.getAttribute("value");
|
||||
if (hgramsProcess &&
|
||||
"processes" in ping.payload &&
|
||||
hgramsProcess in ping.payload.processes) {
|
||||
histograms = ping.payload.processes[hgramsProcess].histograms;
|
||||
}
|
||||
|
||||
hasData = Object.keys(histograms).length > 0;
|
||||
setHasData("histograms-section", hasData);
|
||||
setHasData("histograms-section", hasData || hgramsSelect.options.length);
|
||||
|
||||
if (hasData) {
|
||||
for (let [name, hgram] of Object.entries(histograms)) {
|
||||
|
@ -1950,8 +1993,18 @@ function displayPingData(ping, updatePayloadList = false) {
|
|||
let keyedDiv = document.getElementById("keyed-histograms");
|
||||
removeAllChildNodes(keyedDiv);
|
||||
|
||||
setHasData("keyed-histograms-section", false);
|
||||
let keyedHistograms = payload.keyedHistograms;
|
||||
|
||||
let keyedHgramsSelect = document.getElementById("keyed-histograms-processes");
|
||||
let keyedHgramsOption = keyedHgramsSelect.selectedOptions.item(0);
|
||||
let keyedHgramsProcess = keyedHgramsOption.getAttribute("value");
|
||||
if (keyedHgramsProcess &&
|
||||
"processes" in ping.payload &&
|
||||
keyedHgramsProcess in ping.payload.processes) {
|
||||
keyedHistograms = ping.payload.processes[keyedHgramsProcess].keyedHistograms;
|
||||
}
|
||||
|
||||
setHasData("keyed-histograms-section", keyedHgramsSelect.options.length);
|
||||
if (keyedHistograms) {
|
||||
let hasData = false;
|
||||
for (let [id, keyed] of Object.entries(keyedHistograms)) {
|
||||
|
@ -1960,7 +2013,7 @@ function displayPingData(ping, updatePayloadList = false) {
|
|||
KeyedHistogram.render(keyedDiv, id, keyed, {unpacked: true});
|
||||
}
|
||||
}
|
||||
setHasData("keyed-histograms-section", hasData);
|
||||
setHasData("keyed-histograms-section", hasData || keyedHgramsSelect.options.length);
|
||||
}
|
||||
|
||||
// Show addon histogram data
|
||||
|
|
|
@ -152,6 +152,9 @@
|
|||
<span class="filter-ui">
|
||||
&aboutTelemetry.filterText; <input type="text" class="filter" id="histograms-filter" target_id="histograms"/>
|
||||
</span>
|
||||
<div class="processes-ui">
|
||||
<select id="histograms-processes" class="process-picker"></select>
|
||||
</div>
|
||||
<div id="histograms" class="data">
|
||||
</div>
|
||||
</section>
|
||||
|
@ -161,6 +164,9 @@
|
|||
<h1 class="section-name">&aboutTelemetry.keyedHistogramsSection;</h1>
|
||||
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
|
||||
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
|
||||
<div class="processes-ui">
|
||||
<select id="keyed-histograms-processes" class="process-picker"></select>
|
||||
</div>
|
||||
<div id="keyed-histograms" class="data">
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gfxPrefs.h"
|
||||
#include "mozilla/BasicEvents.h"
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/InternalMutationEvent.h"
|
||||
|
@ -412,35 +413,15 @@ WidgetInputEvent::AccelModifier()
|
|||
* mozilla::WidgetWheelEvent (MouseEvents.h)
|
||||
******************************************************************************/
|
||||
|
||||
bool WidgetWheelEvent::sInitialized = false;
|
||||
bool WidgetWheelEvent::sIsSystemScrollSpeedOverrideEnabled = false;
|
||||
int32_t WidgetWheelEvent::sOverrideFactorX = 0;
|
||||
int32_t WidgetWheelEvent::sOverrideFactorY = 0;
|
||||
|
||||
/* static */ void
|
||||
WidgetWheelEvent::Initialize()
|
||||
{
|
||||
if (sInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
Preferences::AddBoolVarCache(&sIsSystemScrollSpeedOverrideEnabled,
|
||||
"mousewheel.system_scroll_override_on_root_content.enabled", false);
|
||||
Preferences::AddIntVarCache(&sOverrideFactorX,
|
||||
"mousewheel.system_scroll_override_on_root_content.horizontal.factor", 0);
|
||||
Preferences::AddIntVarCache(&sOverrideFactorY,
|
||||
"mousewheel.system_scroll_override_on_root_content.vertical.factor", 0);
|
||||
sInitialized = true;
|
||||
}
|
||||
|
||||
/* static */ double
|
||||
WidgetWheelEvent::ComputeOverriddenDelta(double aDelta, bool aIsForVertical)
|
||||
{
|
||||
Initialize();
|
||||
if (!sIsSystemScrollSpeedOverrideEnabled) {
|
||||
if (!gfxPrefs::MouseWheelHasRootScrollDeltaOverride()) {
|
||||
return aDelta;
|
||||
}
|
||||
int32_t intFactor = aIsForVertical ? sOverrideFactorY : sOverrideFactorX;
|
||||
int32_t intFactor = aIsForVertical
|
||||
? gfxPrefs::MouseWheelRootScrollVerticalFactor()
|
||||
: gfxPrefs::MouseWheelRootScrollHorizontalFactor();
|
||||
// Making the scroll speed slower doesn't make sense. So, ignore odd factor
|
||||
// which is less than 1.0.
|
||||
if (intFactor <= 100) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче