Bug 783630 - Make OOP console logs only show up once in logcat. r=bzbarsky, a=sicking
authorDave Hylands <dhylands@mozilla.com>
Fri, 09 Nov 2012 09:52:09 -0800
changeset 117507 e3cf3f457660e903dc78e533d96e7207d5d8a749
parent 117506 449d3d4c7b536412cdf25366fe862b617c20e602
child 117508 4ddf7580bfea15037b14f85dddd8abefa257a368
push id18
push userryanvm@gmail.com
push dateThu, 13 Dec 2012 01:33:05 +0000
reviewersbzbarsky, sicking
bugs783630
milestone18.0
Bug 783630 - Make OOP console logs only show up once in logcat. r=bzbarsky, a=sicking
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
xpcom/base/nsConsoleService.cpp
xpcom/base/nsConsoleService.h
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -43,16 +43,17 @@
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsAppRunner.h"
 #include "nsAutoPtr.h"
 #include "nsCExternalHandlerService.h"
 #include "nsCOMPtr.h"
 #include "nsChromeRegistryChrome.h"
 #include "nsConsoleMessage.h"
+#include "nsConsoleService.h"
 #include "nsDebugImpl.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsDOMFile.h"
 #include "nsExternalHelperAppService.h"
 #include "nsFrameMessageManager.h"
 #include "nsHashPropertyBag.h"
 #include "nsIAlertsService.h"
 #include "nsIClipboard.h"
@@ -613,16 +614,18 @@ ContentParent::ActorDestroy(ActorDestroy
     InfallibleTArray<MemoryReport> empty;
     SetChildMemoryReporters(empty);
 
     // remove the global remote preferences observers
     Preferences::RemoveObserver(this, "");
 
     RecvRemoveGeolocationListener();
 
+    mConsoleService = nullptr;
+
     nsCOMPtr<nsIThreadInternal>
         threadInt(do_QueryInterface(NS_GetCurrentThread()));
     if (threadInt)
         threadInt->RemoveObserver(this);
     if (mRunToCompletionDepth)
         mRunToCompletionDepth = 0;
 
     MarkAsDead();
@@ -1922,48 +1925,67 @@ ContentParent::RecvRemoveGeolocationList
 
 NS_IMETHODIMP
 ContentParent::HandleEvent(nsIDOMGeoPosition* postion)
 {
   unused << SendGeolocationUpdate(GeoPosition(postion));
   return NS_OK;
 }
 
+nsConsoleService *
+ContentParent::GetConsoleService()
+{
+    if (mConsoleService) {
+        return mConsoleService.get();
+    }
+
+    // Get the ConsoleService by CID rather than ContractID, so that we
+    // can cast the returned pointer to an nsConsoleService (rather than
+    // just an nsIConsoleService). This allows us to call the non-idl function
+    // nsConsoleService::LogMessageWithMode.
+    NS_DEFINE_CID(consoleServiceCID, NS_CONSOLESERVICE_CID);
+    nsCOMPtr<nsConsoleService>  consoleService(do_GetService(consoleServiceCID));
+    mConsoleService = consoleService;
+    return mConsoleService.get();
+}
+
 bool
 ContentParent::RecvConsoleMessage(const nsString& aMessage)
 {
-  nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
-  if (!svc)
+  nsRefPtr<nsConsoleService> consoleService = GetConsoleService();
+  if (!consoleService) {
     return true;
+  }
   
   nsRefPtr<nsConsoleMessage> msg(new nsConsoleMessage(aMessage.get()));
-  svc->LogMessage(msg);
+  consoleService->LogMessageWithMode(msg, nsConsoleService::SuppressLog);
   return true;
 }
 
 bool
 ContentParent::RecvScriptError(const nsString& aMessage,
                                       const nsString& aSourceName,
                                       const nsString& aSourceLine,
                                       const uint32_t& aLineNumber,
                                       const uint32_t& aColNumber,
                                       const uint32_t& aFlags,
                                       const nsCString& aCategory)
 {
-  nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
-  if (!svc)
-      return true;
+  nsRefPtr<nsConsoleService> consoleService = GetConsoleService();
+  if (!consoleService) {
+    return true;
+  }
 
   nsCOMPtr<nsIScriptError> msg(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
   nsresult rv = msg->Init(aMessage, aSourceName, aSourceLine,
                           aLineNumber, aColNumber, aFlags, aCategory.get());
   if (NS_FAILED(rv))
     return true;
 
-  svc->LogMessage(msg);
+  consoleService->LogMessageWithMode(msg, nsConsoleService::SuppressLog);
   return true;
 }
 
 bool
 ContentParent::RecvPrivateDocShellsExist(const bool& aExist)
 {
   if (!gPrivateContent)
     gPrivateContent = new nsTArray<ContentParent*>();
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -25,16 +25,17 @@
 #include "nsIMemoryReporter.h"
 #include "nsCOMArray.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 
 #define CHILD_PROCESS_SHUTDOWN_MESSAGE NS_LITERAL_STRING("child-process-shutdown")
 
 class mozIApplication;
+class nsConsoleService;
 class nsIDOMBlob;
 
 namespace mozilla {
 
 namespace ipc {
 class OptionalURIParams;
 class URIParams;
 class TestShellParent;
@@ -340,14 +341,17 @@ private:
     // True after the OS-level shutdown sequence has been initiated.
     // After going true, any use of this at all, including lingering
     // IPC traffic passing through, will cause assertions to fail.
     bool mIsDestroyed;
     bool mSendPermissionUpdates;
     bool mIsForBrowser;
 
     friend class CrashReporterParent;
+
+    nsRefPtr<nsConsoleService>  mConsoleService;
+    already_AddRefed<nsConsoleService> GetConsoleService();
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/xpcom/base/nsConsoleService.cpp
+++ b/xpcom/base/nsConsoleService.cpp
@@ -138,16 +138,22 @@ CollectCurrentListeners(nsISupports* aKe
 }
 
 } // anonymous namespace
 
 // nsIConsoleService methods
 NS_IMETHODIMP
 nsConsoleService::LogMessage(nsIConsoleMessage *message)
 {
+    return LogMessageWithMode(message, OutputToLog);
+}
+
+nsresult
+nsConsoleService::LogMessageWithMode(nsIConsoleMessage *message, nsConsoleService::OutputMode outputMode)
+{
     if (message == nullptr)
         return NS_ERROR_INVALID_ARG;
 
     if (!sLoggingEnabled) {
         return NS_OK;
     }
 
     if (NS_IsMainThread() && mDeliveringMessage) {
@@ -163,16 +169,17 @@ nsConsoleService::LogMessage(nsIConsoleM
     /*
      * Lock while updating buffer, and while taking snapshot of
      * listeners array.
      */
     {
         MutexAutoLock lock(mLock);
 
 #if defined(ANDROID)
+        if (outputMode == OutputToLog)
         {
             nsXPIDLString msg;
             message->GetMessageMoz(getter_Copies(msg));
             __android_log_print(ANDROID_LOG_ERROR, "GeckoConsole",
                         "%s",
                         NS_LossyConvertUTF16toASCII(msg).get());
         }
 #endif
--- a/xpcom/base/nsConsoleService.h
+++ b/xpcom/base/nsConsoleService.h
@@ -35,16 +35,26 @@ public:
     }
 
     void SetDoneDelivering() {
         MOZ_ASSERT(NS_IsMainThread());
         MOZ_ASSERT(mDeliveringMessage);
         mDeliveringMessage = false;
     }
 
+    // This is a variant of LogMessage which allows the caller to determine
+    // if the message should be output to an OS-specific log. This is used on
+    // B2G to control whether the message is logged to the android log or not.
+
+    enum OutputMode {
+        SuppressLog,
+        OutputToLog
+    };
+    virtual nsresult LogMessageWithMode(nsIConsoleMessage *message, OutputMode outputMode);
+
 private:
     ~nsConsoleService();
 
     // Circular buffer of saved messages
     nsIConsoleMessage **mMessages;
 
     // How big?
     uint32_t mBufferSize;