xpcom/ds/nsObserverService.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "prlog.h"
     7 #include "nsAutoPtr.h"
     8 #include "nsIObserverService.h"
     9 #include "nsIObserver.h"
    10 #include "nsObserverService.h"
    11 #include "nsObserverList.h"
    12 #include "nsThreadUtils.h"
    13 #include "nsEnumeratorUtils.h"
    14 #include "mozilla/net/NeckoCommon.h"
    15 #include "mozilla/Services.h"
    17 #define NOTIFY_GLOBAL_OBSERVERS
    19 #if defined(PR_LOGGING)
    20 // Log module for nsObserverService logging...
    21 //
    22 // To enable logging (see prlog.h for full details):
    23 //
    24 //    set NSPR_LOG_MODULES=ObserverService:5
    25 //    set NSPR_LOG_FILE=nspr.log
    26 //
    27 // this enables PR_LOG_DEBUG level information and places all output in
    28 // the file nspr.log
    29 static PRLogModuleInfo*
    30 GetObserverServiceLog()
    31 {
    32     static PRLogModuleInfo *sLog;
    33     if (!sLog)
    34         sLog = PR_NewLogModule("ObserverService");
    35     return sLog;
    36 }
    37   #define LOG(x)  PR_LOG(GetObserverServiceLog(), PR_LOG_DEBUG, x)
    38 #else
    39   #define LOG(x)
    40 #endif /* PR_LOGGING */
    42 namespace mozilla {
    44 struct SuspectObserver {
    45     SuspectObserver(const char* aTopic, size_t aReferentCount)
    46         : topic(aTopic), referentCount(aReferentCount) {}
    47     const char* topic;
    48     size_t referentCount;
    49 };
    51 struct ObserverServiceReferentCount {
    52     ObserverServiceReferentCount()
    53         : numStrong(0), numWeakAlive(0), numWeakDead(0) {}
    54     size_t numStrong;
    55     size_t numWeakAlive;
    56     size_t numWeakDead;
    57     nsTArray<SuspectObserver> suspectObservers;
    58 };
    60 } // namespace mozilla
    62 using namespace mozilla;
    64 PLDHashOperator
    65 nsObserverService::CountReferents(nsObserverList* aObserverList,
    66                                   void* aClosure)
    67 {
    68     if (!aObserverList) {
    69         return PL_DHASH_NEXT;
    70     }
    72     ObserverServiceReferentCount* referentCount =
    73         static_cast<ObserverServiceReferentCount*>(aClosure);
    75     size_t numStrong = 0;
    76     size_t numWeakAlive = 0;
    77     size_t numWeakDead = 0;
    79     nsTArray<ObserverRef>& observers = aObserverList->mObservers;
    80     for (uint32_t i = 0; i < observers.Length(); i++) {
    81         if (observers[i].isWeakRef) {
    82             nsCOMPtr<nsIObserver> observerRef(
    83                 do_QueryReferent(observers[i].asWeak()));
    84             if (observerRef) {
    85                 numWeakAlive++;
    86             } else {
    87                 numWeakDead++;
    88             }
    89         } else {
    90             numStrong++;
    91         }
    92     }
    94     referentCount->numStrong += numStrong;
    95     referentCount->numWeakAlive += numWeakAlive;
    96     referentCount->numWeakDead += numWeakDead;
    98     // Keep track of topics that have a suspiciously large number
    99     // of referents (symptom of leaks).
   100     size_t total = numStrong + numWeakAlive + numWeakDead;
   101     if (total > kSuspectReferentCount) {
   102         SuspectObserver suspect(aObserverList->GetKey(), total);
   103         referentCount->suspectObservers.AppendElement(suspect);
   104     }
   106     return PL_DHASH_NEXT;
   107 }
   109 NS_IMETHODIMP
   110 nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport,
   111                                   nsISupports* aData)
   112 {
   113     ObserverServiceReferentCount referentCount;
   114     mObserverTopicTable.EnumerateEntries(CountReferents, &referentCount);
   116     nsresult rv;
   117     for (uint32_t i = 0; i < referentCount.suspectObservers.Length(); i++) {
   118         SuspectObserver& suspect = referentCount.suspectObservers[i];
   119         nsPrintfCString suspectPath("observer-service-suspect/"
   120                                     "referent(topic=%s)",
   121                                     suspect.topic);
   122         rv = aHandleReport->Callback(/* process */ EmptyCString(),
   123             suspectPath, KIND_OTHER, UNITS_COUNT, suspect.referentCount,
   124             NS_LITERAL_CSTRING("A topic with a suspiciously large number of "
   125                                "referents.  This may be symptomatic of a leak "
   126                                "if the number of referents is high with "
   127                                "respect to the number of windows."),
   128             aData);
   130       if (NS_WARN_IF(NS_FAILED(rv)))
   131           return rv;
   132     }
   134     rv = aHandleReport->Callback(/* process */ EmptyCString(),
   135         NS_LITERAL_CSTRING("observer-service/referent/strong"),
   136         KIND_OTHER, UNITS_COUNT, referentCount.numStrong,
   137         NS_LITERAL_CSTRING("The number of strong references held by the "
   138                            "observer service."),
   139         aData);
   141     if (NS_WARN_IF(NS_FAILED(rv)))
   142         return rv;
   144     rv = aHandleReport->Callback(/* process */ EmptyCString(),
   145         NS_LITERAL_CSTRING("observer-service/referent/weak/alive"),
   146         KIND_OTHER, UNITS_COUNT, referentCount.numWeakAlive,
   147         NS_LITERAL_CSTRING("The number of weak references held by the "
   148                            "observer service that are still alive."),
   149         aData);
   151     if (NS_WARN_IF(NS_FAILED(rv)))
   152         return rv;
   154     rv = aHandleReport->Callback(/* process */ EmptyCString(),
   155         NS_LITERAL_CSTRING("observer-service/referent/weak/dead"),
   156         KIND_OTHER, UNITS_COUNT, referentCount.numWeakDead,
   157         NS_LITERAL_CSTRING("The number of weak references held by the "
   158                            "observer service that are dead."),
   159         aData);
   161     if (NS_WARN_IF(NS_FAILED(rv)))
   162         return rv;
   164     return NS_OK;
   165 }
   167 ////////////////////////////////////////////////////////////////////////////////
   168 // nsObserverService Implementation
   171 NS_IMPL_ISUPPORTS(
   172     nsObserverService,
   173     nsIObserverService,
   174     nsObserverService,
   175     nsIMemoryReporter)
   177 nsObserverService::nsObserverService() :
   178     mShuttingDown(false)
   179 {
   180 }
   182 nsObserverService::~nsObserverService(void)
   183 {
   184     Shutdown();
   185 }
   187 void
   188 nsObserverService::RegisterReporter()
   189 {
   190     RegisterWeakMemoryReporter(this);
   191 }
   193 void
   194 nsObserverService::Shutdown()
   195 {
   196     UnregisterWeakMemoryReporter(this);
   198     mShuttingDown = true;
   200     mObserverTopicTable.Clear();
   201 }
   203 nsresult
   204 nsObserverService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
   205 {
   206     LOG(("nsObserverService::Create()"));
   208     nsRefPtr<nsObserverService> os = new nsObserverService();
   210     if (!os)
   211         return NS_ERROR_OUT_OF_MEMORY;
   213     // The memory reporter can not be immediately registered here because
   214     // the nsMemoryReporterManager may attempt to get the nsObserverService
   215     // during initialization, causing a recursive GetService.
   216     nsRefPtr<nsRunnableMethod<nsObserverService> > registerRunnable =
   217         NS_NewRunnableMethod(os, &nsObserverService::RegisterReporter);
   218     NS_DispatchToCurrentThread(registerRunnable);
   220     return os->QueryInterface(aIID, aInstancePtr);
   221 }
   223 #define NS_ENSURE_VALIDCALL \
   224     if (!NS_IsMainThread()) {                                     \
   225         MOZ_CRASH("Using observer service off the main thread!"); \
   226         return NS_ERROR_UNEXPECTED;                               \
   227     }                                                             \
   228     if (mShuttingDown) {                                          \
   229         NS_ERROR("Using observer service after XPCOM shutdown!"); \
   230         return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;                  \
   231     }
   233 NS_IMETHODIMP
   234 nsObserverService::AddObserver(nsIObserver* anObserver, const char* aTopic,
   235                                bool ownsWeak)
   236 {
   237     LOG(("nsObserverService::AddObserver(%p: %s)",
   238          (void*) anObserver, aTopic));
   240     NS_ENSURE_VALIDCALL
   241     if (NS_WARN_IF(!anObserver) || NS_WARN_IF(!aTopic))
   242         return NS_ERROR_INVALID_ARG;
   244     if (mozilla::net::IsNeckoChild() && !strncmp(aTopic, "http-on-", 8)) {
   245       return NS_ERROR_NOT_IMPLEMENTED;
   246     }
   248     nsObserverList *observerList = mObserverTopicTable.PutEntry(aTopic);
   249     if (!observerList)
   250         return NS_ERROR_OUT_OF_MEMORY;
   252     return observerList->AddObserver(anObserver, ownsWeak);
   253 }
   255 NS_IMETHODIMP
   256 nsObserverService::RemoveObserver(nsIObserver* anObserver, const char* aTopic)
   257 {
   258     LOG(("nsObserverService::RemoveObserver(%p: %s)",
   259          (void*) anObserver, aTopic));
   260     NS_ENSURE_VALIDCALL
   261     if (NS_WARN_IF(!anObserver) || NS_WARN_IF(!aTopic))
   262         return NS_ERROR_INVALID_ARG;
   264     nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic);
   265     if (!observerList)
   266         return NS_ERROR_FAILURE;
   268     /* This death grip is to protect against stupid consumers who call
   269        RemoveObserver from their Destructor, see bug 485834/bug 325392. */
   270     nsCOMPtr<nsIObserver> kungFuDeathGrip(anObserver);
   271     return observerList->RemoveObserver(anObserver);
   272 }
   274 NS_IMETHODIMP
   275 nsObserverService::EnumerateObservers(const char* aTopic,
   276                                       nsISimpleEnumerator** anEnumerator)
   277 {
   278     NS_ENSURE_VALIDCALL
   279     if (NS_WARN_IF(!anEnumerator) || NS_WARN_IF(!aTopic))
   280         return NS_ERROR_INVALID_ARG;
   282     nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic);
   283     if (!observerList)
   284         return NS_NewEmptyEnumerator(anEnumerator);
   286     return observerList->GetObserverList(anEnumerator);
   287 }
   289 // Enumerate observers of aTopic and call Observe on each.
   290 NS_IMETHODIMP nsObserverService::NotifyObservers(nsISupports *aSubject,
   291                                                  const char *aTopic,
   292                                                  const char16_t *someData)
   293 {
   294     LOG(("nsObserverService::NotifyObservers(%s)", aTopic));
   296     NS_ENSURE_VALIDCALL
   297     if (NS_WARN_IF(!aTopic))
   298         return NS_ERROR_INVALID_ARG;
   300     nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic);
   301     if (observerList)
   302         observerList->NotifyObservers(aSubject, aTopic, someData);
   304 #ifdef NOTIFY_GLOBAL_OBSERVERS
   305     observerList = mObserverTopicTable.GetEntry("*");
   306     if (observerList)
   307         observerList->NotifyObservers(aSubject, aTopic, someData);
   308 #endif
   310     return NS_OK;
   311 }
   313 static PLDHashOperator
   314 UnmarkGrayObserverEntry(nsObserverList* aObserverList, void* aClosure)
   315 {
   316     if (aObserverList) {
   317         aObserverList->UnmarkGrayStrongObservers();
   318     }
   319     return PL_DHASH_NEXT;
   320 }
   322 NS_IMETHODIMP
   323 nsObserverService::UnmarkGrayStrongObservers()
   324 {
   325     NS_ENSURE_VALIDCALL
   327     mObserverTopicTable.EnumerateEntries(UnmarkGrayObserverEntry, nullptr);
   329     return NS_OK;
   330 }

mercurial