Files
palemoon27/xpcom/ds/nsObserverService.cpp
T
roytam1 f32bf3ebba import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1268976 - Assert that the micro-task queues are empty upon destruction of CycleCollectedJSRuntime; r=mccr8 (a459a4af91)
- Bug 1191354 part 1 - Clean up nsHTMLEditRules::GetHighestInlineParent; r=ehsan (a2f401887c)
- Bug 1191354 part 2 - Clean up nsHTMLEditRules::CheckInterlinePosition; r=ehsan (75d3829eec)
- Bug 1191354 part 3 - Clean up nsHTMLEditRules::InsertMozBRIfNeeded; r=ehsan (bedbba7c14)
- Bug 772796 - Handle newlines correctly when joining <div> and <pre>. r=roc (323eaf4fe9)
- Bug 1258085 - Avoid empty whitespace nodes when editing (b77825fb31)
- Bug 1156062 part 4 - Clean up ns*EditRules::WillInsert; r=ehsan (f351557776)
- Bug 1156062 part 5 - Make CreateBR return regular pointer; r=ehsan (8720917dee)
- Bug 1156062 part 6 - Clean up nsHTMLEditRules::WillInsertBreak; r=ehsan (d71bca568f)
- Bug 1156062 part 7 - Clean up nsHTMLEditRules::StandardBreakImpl; r=ehsan (625db32c02)
- Bug 1156062 part 8 - Clean up nsHTMLEditRules::JoinBlocks; r=ehsan (266b6c5150)
- Bug 1156062 part 9 - Clean up nsHTMLEditRules::WillAlign; r=masayuki (a6e3227001)
- Bug 1156062 part 10 - Clean up MarginPropertyAtomForIndent; r=masayuki (28612e062c)
- Bug 1184665 - Remove a spammy editor warning (a2db555918)
- Bug 1156062 part 11 - Clean up nsHTMLEditRules::Before/AfterEdit; r=masayuki (6be722082e)
- Bug 1156062 part 12 - Clean up nsHTMLEditRules::GetAlignment; r=masayuki (350be10ee8)
- Bug 1190172 part 1 - Clean up nsHTMLEditor::SplitStyleAbovePoint; r=ehsan (ce5e360af6)
- Bug 1145395 - Introduce an overload of nsHTMLEditor::SelElementPosition that takes an Element; r=ehsan (7ca9dfd2f8)
- Bug 1190172 part 2 - Clean up nsHTMLEditor::ClearStyle; r=ehsan (84334514ad)
- Bug 1190172 part 3 - Remove old method variants; r=ehsan (e042bd64d5)
- Bug 1190172 part 4 - Remove unused nsHTMLEditor::HasAttr; r=ehsan (a4f1563465)
- Bug 1190172 part 5 - Clean up nsHTMLEditor::NodeIsProperty; r=ehsan (98afb84bd4)
- Bug 1190172 part 6 - Clean up nsHTMLEditor::RelativeFontChangeOnTextNode; r=ehsan (0bf036d206)
- Bug 1190172 part 7 - Clean up nsHTMLEditor::PromoteInlineRange; r=ehsan (0a21347500)
- Bug 1190172 part 8 - Clean up nsHTMLEditor::PromoteRangeIfStartsOrEndsInNamedAnchor; r=ehsan (78cf619036)
- Bug 1190172 part 9 - Clean up nsHTMLEditor::ReturnInHeader; r=ehsan (1d8d151ff1)
- Bug 1190172 part 10 - Clean up nsHTMLEditor::ReturnInListItem; r=ehsan (0ce94d3cb1)
- Bug 1190172 part 11 - Clean up nsHTMLEditRules::IsEmptyBlock; r=ehsan (a8dc5092f8)
- Bug 1190172 part 12 - Clean up nsHTMLEditRules::ExpandSelectionForDeletion; r=ehsan (3d4a87a56d)
- Bug 1191354 part 4 - Clean up nsHTMLEditRules::AlignBlock; r=ehsan (b39372d726)
- Bug 1191354 part 5 - Clean up nsHTMLEditRules::IsEmptyInline; r=ehsan (0b8ab19fd1)
- Bug 1191354 part 6 - Clean up IsBlockNode/IsInlineNode in nsHTMLEditRules.cpp; r=ehsan (8ba8047e12)
- Bug 1191354 part 7 - Clean up nsHTMLEditRules::CheckForInvisibleBR; r=ehsan (0bc61269bd)
- Bug 1191354 part 8 - Typedefs in headers for readability; r=ehsan (50b43dc3e9)
- Bug 1191354 part 9 - Remove old nsHTMLEditRules::ConvertListType variant; r=ehsan (871f1b30a5)
- Bug 1191354 part 10 - More features for OwningNonNull; r=froydnj (8e365d079a)
- Bug 1191354 part 11 - Clean up nsHTMLEditRules::WillOutdent; r=ehsan (0c59a81c10)
- Bug 1191354 part 12 - Clean up nsHTMLEditRules::OutdentPartOfBlock; r=ehsan (243d7ab42f)
- Bug 1191354 part 13 - Clean up nsHTMLEditRules::SplitBlock; r=ehsan (c1141ab04d)
- Bug 1191356 part 1 - Clean up nsHTMLEditRules::RemoveListStructure; r=ehsan (1d2ad5faa6)
- Bug 1191356 part 2 - Clean up nsHTMLEditor::RemoveBlockContainer; r=ehsan (a9d140f511)
- Bug 1191356 part 3 - Clean up nsHTMLEditRules::MoveBlock; r=ehsan (6bc14cd40c)
- Bug 1191356 part 4 - Clean up nsHTMLEditRules::MoveNodeSmart, MoveContents; r=ehsan (00e6536e47)
- Bug 1191356 part 5 - Clean up nsHTMLEditRules::RelativeChangeIndentationOfElementNode; r=ehsan (c3139c7d90)
- Bug 1191356 part 6 - Clean up nsHTMLEditRules::WillMakeBasicBlock; r=ehsan (b3f73c2e12)
- Bug 1191356 part 7 - Clean up nsHTMLEditor::GetSelectionContainer; r=ehsan (091e999587)
- Bug 1191356 part 8 - Clean up nsHTMLEditRules::WillAbsolutePosition; r=ehsan (9982c65a99)
- Bug 1208884 - Fix a few null check ordering bugs in nsHTMLEditRules::SplitParagraph; r=roc (d04eece297)
- Bug 1209037 - Eliminate some unneeded null checks; r=jdm (b35d5308c5)
- Bug 1191356 part 9 - Convert nsHTMLEditRules::mNewBlock to Element; r=ehsan (f374780e22)
- Bug 1253734 - Add some more editor things to CC traversal. r=mccr8. (94a0c77bb1)
- Bug 1193762 part 1 - Remove nsEditor::IsBlockNode(nsIDOMNode*); r=ehsan (5e107cbdbb)
- Bug 1193762 part 2 - Remove nsHTMLEditor::IsVisBreak(nsIDOMNode*); r=ehsan (5e61c27d21)
- Bug 1193762 part 3 - Remove nsEditor::IsDescendantOfEditorRoot(nsIDOMNode*); r=ehsan (022a37d442)
- Bug 1193762 part 4 - Avoid nsCOMPtr in ternary operator; r=froydnj (e4bc35cbe0)
- Bug 1193762 part 5 - Convert DecodePool::threads to nsTArray; r=froydnj (c61f063f4d)
- Bug 1193762 part 6 - Return raw pointer, not nsCOMPtr; r=froydnj (a43c30f92e)
- Bug 1193762 part 7 - Use .get() when assigning to variables; r=froydnj (a61ad819f0)
- Bug 1193762 part 8 - Fix things that will break; r=froydnj (40a76db662)
- Bug 1193762 part 9 - Delete nsCOMPtr<T>::operator T*()&&; r=froydnj (022c1f0dba)
- Bug 1168223 - Fix a crash caused by unexpected flushes under nsIEditor::SetFlags. r=ehsan (cc49d468b8)
- Bug 1158837 - Ensure the start and end nodes are non-null before using them. r=roc (7c28121aa7)
- Bug 1269047 - Remove chained ENSURE calls from GetStartNodeAndOffset. r=ehsan (f36c1c67aa)
- Bug 1248078 - Remove the dedicated scroll acknowledgement message. r=botond (500b8d7574)
- Bug 1260806: Remove some more dead MessageLoop code. r=jld (1c223cafe8)
- Bug 1266595: Replace Chromium Task with Runnable. r=froydnj (5c1c056c83)
- Bug 1242343 - p1. ConstructSystem32Path from LoadLibrarySystem32 - r=jimm (b28fcbc0c4)
- Bug 1242343 - p2. Blacklist msmpeg2vdec.dll 12.0.9200.16426 & .17037 - r=cpearce (9a71795ab0)
- Bug 1253395 - Disable msmpeg2vdec.dll blackslisting - r=cpearce (e1d4dc47be)
- Bug 1242456 - Create RAIIs to manage HGLOBAL and printer HANDLE in ShowNativePrintDialog and CreateGlobalDevModeAndInit. r=jimm, r=bobowen (a22cecaebd)
- Bug 1262399 - remove Impl suffixes from nsSupports* implementations; r=mccr8 (6733db9394)
- Bug 1268772 (part 1) - Remove nsCheapSet::Put()'s return value. r=erahm. (5f3f553e84)
- Bug 1268772 (part 2) - Make infallible nsVariant methods return |void| instead of |nsresult|. r=erahm. (22ae74fdaf)
- Bug 1268772 (part 3) - Remove NS_NewWindowsRegKey()'s return value. r=erahm. (dc32bd698e)
- Bug 1268772 (part 4) - Use MOZ_MUST_USE with NS_NewISupportsArray(). r=erahm. (e51ecfdf9f)
- Bug 1268772 (part 5) - Use MOZ_MUST_USE in other parts of xpcom/ds/. r=erahm. (4d8a5183eb)
- Bug 1266027 part 1 - make the MediaDecoderReaderWrapper as a proxy of requesting media data; r=jwwang (fbaa79019d)
- Bug 1195601 - Remove MediaDecoderStateMachine::mLogicallySeeking. r=kinetik. (5ab1ff1ca0)
- Bug 1266027 part 2 - make MDSM and SeekTask to adopt new MediaDecoderReaderWrapper API; r=jwwang (1961e26e80)
- add mac specific dupes (4e4ff4b123)
- Bug 1269262 - Unbreak build without NO_EXPAND_LIBS in js/src/moz.build after bug 1239083. r=ted (46d2dec64a)
- Bug 1253215 - Initialize RequestSyncService only if its pref is enabled, r=ehsan (aec1b2f889)
- Bug 1269303 - Remove RequestSync API, r=fabrice (f774336e34)
2024-08-26 16:01:17 +08:00

336 lines
10 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/Logging.h"
#include "nsAutoPtr.h"
#include "nsIConsoleService.h"
#include "nsIObserverService.h"
#include "nsIObserver.h"
#include "nsIScriptError.h"
#include "nsObserverService.h"
#include "nsObserverList.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "nsEnumeratorUtils.h"
#include "xpcpublic.h"
#include "mozilla/net/NeckoCommon.h"
#include "mozilla/Services.h"
#define NOTIFY_GLOBAL_OBSERVERS
// Log module for nsObserverService logging...
//
// To enable logging (see prlog.h for full details):
//
// set NSPR_LOG_MODULES=ObserverService:5
// set NSPR_LOG_FILE=nspr.log
//
// this enables LogLevel::Debug level information and places all output in
// the file nspr.log
static mozilla::LazyLogModule sObserverServiceLog("ObserverService");
#define LOG(x) MOZ_LOG(sObserverServiceLog, mozilla::LogLevel::Debug, x)
using namespace mozilla;
NS_IMETHODIMP
nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize)
{
struct SuspectObserver
{
SuspectObserver(const char* aTopic, size_t aReferentCount)
: mTopic(aTopic)
, mReferentCount(aReferentCount)
{}
const char* mTopic;
size_t mReferentCount;
};
size_t totalNumStrong = 0;
size_t totalNumWeakAlive = 0;
size_t totalNumWeakDead = 0;
nsTArray<SuspectObserver> suspectObservers;
for (auto iter = mObserverTopicTable.Iter(); !iter.Done(); iter.Next()) {
nsObserverList* observerList = iter.Get();
if (!observerList) {
continue;
}
size_t topicNumStrong = 0;
size_t topicNumWeakAlive = 0;
size_t topicNumWeakDead = 0;
nsTArray<ObserverRef>& observers = observerList->mObservers;
for (uint32_t i = 0; i < observers.Length(); i++) {
if (observers[i].isWeakRef) {
nsCOMPtr<nsIObserver> observerRef(
do_QueryReferent(observers[i].asWeak()));
if (observerRef) {
topicNumWeakAlive++;
} else {
topicNumWeakDead++;
}
} else {
topicNumStrong++;
}
}
totalNumStrong += topicNumStrong;
totalNumWeakAlive += topicNumWeakAlive;
totalNumWeakDead += topicNumWeakDead;
// Keep track of topics that have a suspiciously large number
// of referents (symptom of leaks).
size_t topicTotal = topicNumStrong + topicNumWeakAlive + topicNumWeakDead;
if (topicTotal > kSuspectReferentCount) {
SuspectObserver suspect(observerList->GetKey(), topicTotal);
suspectObservers.AppendElement(suspect);
}
}
// These aren't privacy-sensitive and so don't need anonymizing.
nsresult rv;
for (uint32_t i = 0; i < suspectObservers.Length(); i++) {
SuspectObserver& suspect = suspectObservers[i];
nsPrintfCString suspectPath("observer-service-suspect/referent(topic=%s)",
suspect.mTopic);
rv = aHandleReport->Callback(
/* process */ EmptyCString(),
suspectPath, KIND_OTHER, UNITS_COUNT, suspect.mReferentCount,
NS_LITERAL_CSTRING("A topic with a suspiciously large number of "
"referents. This may be symptomatic of a leak "
"if the number of referents is high with "
"respect to the number of windows."),
aData);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
rv = aHandleReport->Callback(
/* process */ EmptyCString(),
NS_LITERAL_CSTRING("observer-service/referent/strong"),
KIND_OTHER, UNITS_COUNT, totalNumStrong,
NS_LITERAL_CSTRING("The number of strong references held by the "
"observer service."),
aData);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = aHandleReport->Callback(
/* process */ EmptyCString(),
NS_LITERAL_CSTRING("observer-service/referent/weak/alive"),
KIND_OTHER, UNITS_COUNT, totalNumWeakAlive,
NS_LITERAL_CSTRING("The number of weak references held by the "
"observer service that are still alive."),
aData);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = aHandleReport->Callback(
/* process */ EmptyCString(),
NS_LITERAL_CSTRING("observer-service/referent/weak/dead"),
KIND_OTHER, UNITS_COUNT, totalNumWeakDead,
NS_LITERAL_CSTRING("The number of weak references held by the "
"observer service that are dead."),
aData);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsObserverService Implementation
NS_IMPL_ISUPPORTS(nsObserverService,
nsIObserverService,
nsObserverService,
nsIMemoryReporter)
nsObserverService::nsObserverService()
: mShuttingDown(false)
{
}
nsObserverService::~nsObserverService(void)
{
Shutdown();
}
void
nsObserverService::RegisterReporter()
{
RegisterWeakMemoryReporter(this);
}
void
nsObserverService::Shutdown()
{
UnregisterWeakMemoryReporter(this);
mShuttingDown = true;
mObserverTopicTable.Clear();
}
nsresult
nsObserverService::Create(nsISupports* aOuter, const nsIID& aIID,
void** aInstancePtr)
{
LOG(("nsObserverService::Create()"));
RefPtr<nsObserverService> os = new nsObserverService();
if (!os) {
return NS_ERROR_OUT_OF_MEMORY;
}
// The memory reporter can not be immediately registered here because
// the nsMemoryReporterManager may attempt to get the nsObserverService
// during initialization, causing a recursive GetService.
RefPtr<nsRunnableMethod<nsObserverService>> registerRunnable =
NS_NewRunnableMethod(os, &nsObserverService::RegisterReporter);
NS_DispatchToCurrentThread(registerRunnable);
return os->QueryInterface(aIID, aInstancePtr);
}
#define NS_ENSURE_VALIDCALL \
if (!NS_IsMainThread()) { \
MOZ_CRASH("Using observer service off the main thread!"); \
return NS_ERROR_UNEXPECTED; \
} \
if (mShuttingDown) { \
NS_ERROR("Using observer service after XPCOM shutdown!"); \
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; \
}
NS_IMETHODIMP
nsObserverService::AddObserver(nsIObserver* aObserver, const char* aTopic,
bool aOwnsWeak)
{
LOG(("nsObserverService::AddObserver(%p: %s)",
(void*)aObserver, aTopic));
NS_ENSURE_VALIDCALL
if (NS_WARN_IF(!aObserver) || NS_WARN_IF(!aTopic)) {
return NS_ERROR_INVALID_ARG;
}
if (mozilla::net::IsNeckoChild() && !strncmp(aTopic, "http-on-", 8)) {
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
error->Init(NS_LITERAL_STRING("http-on-* observers only work in the parent process"),
EmptyString(), EmptyString(), 0, 0,
nsIScriptError::warningFlag, "chrome javascript");
console->LogMessage(error);
return NS_ERROR_NOT_IMPLEMENTED;
}
nsObserverList* observerList = mObserverTopicTable.PutEntry(aTopic);
if (!observerList) {
return NS_ERROR_OUT_OF_MEMORY;
}
return observerList->AddObserver(aObserver, aOwnsWeak);
}
NS_IMETHODIMP
nsObserverService::RemoveObserver(nsIObserver* aObserver, const char* aTopic)
{
LOG(("nsObserverService::RemoveObserver(%p: %s)",
(void*)aObserver, aTopic));
NS_ENSURE_VALIDCALL
if (NS_WARN_IF(!aObserver) || NS_WARN_IF(!aTopic)) {
return NS_ERROR_INVALID_ARG;
}
nsObserverList* observerList = mObserverTopicTable.GetEntry(aTopic);
if (!observerList) {
return NS_ERROR_FAILURE;
}
/* This death grip is to protect against stupid consumers who call
RemoveObserver from their Destructor, see bug 485834/bug 325392. */
nsCOMPtr<nsIObserver> kungFuDeathGrip(aObserver);
return observerList->RemoveObserver(aObserver);
}
NS_IMETHODIMP
nsObserverService::EnumerateObservers(const char* aTopic,
nsISimpleEnumerator** anEnumerator)
{
NS_ENSURE_VALIDCALL
if (NS_WARN_IF(!anEnumerator) || NS_WARN_IF(!aTopic)) {
return NS_ERROR_INVALID_ARG;
}
nsObserverList* observerList = mObserverTopicTable.GetEntry(aTopic);
if (!observerList) {
return NS_NewEmptyEnumerator(anEnumerator);
}
observerList->GetObserverList(anEnumerator);
return NS_OK;
}
// Enumerate observers of aTopic and call Observe on each.
NS_IMETHODIMP nsObserverService::NotifyObservers(nsISupports* aSubject,
const char* aTopic,
const char16_t* aSomeData)
{
LOG(("nsObserverService::NotifyObservers(%s)", aTopic));
NS_ENSURE_VALIDCALL
if (NS_WARN_IF(!aTopic)) {
return NS_ERROR_INVALID_ARG;
}
nsObserverList* observerList = mObserverTopicTable.GetEntry(aTopic);
if (observerList) {
observerList->NotifyObservers(aSubject, aTopic, aSomeData);
}
#ifdef NOTIFY_GLOBAL_OBSERVERS
observerList = mObserverTopicTable.GetEntry("*");
if (observerList) {
observerList->NotifyObservers(aSubject, aTopic, aSomeData);
}
#endif
return NS_OK;
}
NS_IMETHODIMP
nsObserverService::UnmarkGrayStrongObservers()
{
NS_ENSURE_VALIDCALL
nsCOMArray<nsIObserver> strongObservers;
for (auto iter = mObserverTopicTable.Iter(); !iter.Done(); iter.Next()) {
nsObserverList* aObserverList = iter.Get();
if (aObserverList) {
aObserverList->AppendStrongObservers(strongObservers);
}
}
for (uint32_t i = 0; i < strongObservers.Length(); ++i) {
xpc_TryUnmarkWrappedGrayObject(strongObservers[i]);
}
return NS_OK;
}