Bug 1004306 - AudioChannelService should drop references to Agents when their window is destroyed, r=mchen, r=rlin
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 17 Oct 2014 16:29:39 +0100
changeset 211053 5bbe8b64b4b7acca37f269d19c5d1d238fa87586
parent 211052 76686694c568a13a9e1a7b1efed2c5632bd81c06
child 211054 288827a46e4def427c5e17317928d7d5ba5629d9
push id27667
push usercbook@mozilla.com
push dateMon, 20 Oct 2014 12:40:56 +0000
treeherdermozilla-central@cc2d8bdbccb8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmchen, rlin
bugs1004306
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1004306 - AudioChannelService should drop references to Agents when their window is destroyed, r=mchen, r=rlin
dom/audiochannel/AudioChannelService.cpp
dom/audiochannel/AudioChannelService.h
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -10,16 +10,17 @@
 #include "base/basictypes.h"
 
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/unused.h"
 
 #include "mozilla/dom/ContentParent.h"
 
+#include "nsISupportsPrimitives.h"
 #include "nsThreadUtils.h"
 #include "nsHashPropertyBag.h"
 #include "nsComponentManagerUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #ifdef MOZ_WIDGET_GONK
@@ -107,16 +108,17 @@ AudioChannelService::AudioChannelService
 , mDisabled(false)
 , mDefChannelChildID(CONTENT_PROCESS_ID_UNKNOWN)
 {
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->AddObserver(this, "ipc:content-shutdown", false);
       obs->AddObserver(this, "xpcom-shutdown", false);
+      obs->AddObserver(this, "inner-window-destroyed", false);
 #ifdef MOZ_WIDGET_GONK
       // To monitor the volume settings based on audio channel.
       obs->AddObserver(this, "mozsettings-changed", false);
 #endif
     }
   }
 }
 
@@ -217,16 +219,17 @@ AudioChannelService::UnregisterAudioChan
 
   nsAutoPtr<AudioChannelAgentData> data;
   mAgents.RemoveAndForget(aAgent, data);
 
   if (data) {
     UnregisterType(data->mChannel, data->mElementHidden,
                    CONTENT_PROCESS_ID_MAIN, data->mWithVideo);
   }
+
 #ifdef MOZ_WIDGET_GONK
   bool active = AnyAudioChannelIsActive();
   for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
     mSpeakerManager[i]->SetAudioChannelActive(active);
   }
 #endif
 
   // If this is the last agent for this window, we must notify the observers.
@@ -741,16 +744,38 @@ AudioChannelService::ChannelsActiveWithH
     if (!mChannelCounters[i].IsEmpty()) {
       return true;
     }
   }
 
   return false;
 }
 
+PLDHashOperator
+AudioChannelService::WindowDestroyedEnumerator(AudioChannelAgent* aAgent,
+                                               nsAutoPtr<AudioChannelAgentData>& aData,
+                                               void* aPtr)
+{
+  uint64_t* innerID = static_cast<uint64_t*>(aPtr);
+  MOZ_ASSERT(innerID);
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aAgent->Window());
+  if (!window || window->WindowID() != *innerID) {
+    return PL_DHASH_NEXT;
+  }
+
+  AudioChannelService* service = AudioChannelService::GetAudioChannelService();
+  MOZ_ASSERT(service);
+
+  service->UnregisterType(aData->mChannel, aData->mElementHidden,
+                          CONTENT_PROCESS_ID_MAIN, aData->mWithVideo);
+
+  return PL_DHASH_REMOVE;
+}
+
 NS_IMETHODIMP
 AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
 {
   if (!strcmp(aTopic, "xpcom-shutdown")) {
     mDisabled = true;
   }
 
   if (!strcmp(aTopic, "ipc:content-shutdown")) {
@@ -793,16 +818,17 @@ AudioChannelService::Observe(nsISupports
       if (mDefChannelChildID == childID) {
         SetDefaultVolumeControlChannelInternal(-1, false, childID);
         mDefChannelChildID = CONTENT_PROCESS_ID_UNKNOWN;
       }
     } else {
       NS_WARNING("ipc:content-shutdown message without childID property");
     }
   }
+
 #ifdef MOZ_WIDGET_GONK
   // To process the volume control on each audio channel according to
   // change of settings
   else if (!strcmp(aTopic, "mozsettings-changed")) {
     AutoJSAPI jsapi;
     jsapi.Init();
     JSContext* cx = jsapi.cx();
     RootedDictionary<SettingChangeNotification> setting(cx);
@@ -834,16 +860,36 @@ AudioChannelService::Observe(nsISupports
       // We didn't use MOZ_CRASH or MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE here
       // because any web content who has permission of mozSettings can set any
       // names then it can be easy to crash the B2G.
       NS_WARNING("unexpected audio channel for volume control");
     }
   }
 #endif
 
+  else if (!strcmp(aTopic, "inner-window-destroyed")) {
+    nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
+    NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
+
+    uint64_t innerID;
+    nsresult rv = wrapper->GetData(&innerID);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    mAgents.Enumerate(WindowDestroyedEnumerator, &innerID);
+
+#ifdef MOZ_WIDGET_GONK
+    bool active = AnyAudioChannelIsActive();
+    for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
+      mSpeakerManager[i]->SetAudioChannelActive(active);
+    }
+#endif
+  }
+
   return NS_OK;
 }
 
 AudioChannelService::AudioChannelInternalType
 AudioChannelService::GetInternalType(AudioChannel aChannel,
                                      bool aElementHidden)
 {
   switch (aChannel) {
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -216,16 +216,21 @@ protected:
                                 AudioChannelAgentData* aUnused,
                                 void *aPtr);
 
   static PLDHashOperator
   CountWindowEnumerator(AudioChannelAgent* aAgent,
                         AudioChannelAgentData* aUnused,
                         void *aPtr);
 
+  static PLDHashOperator
+  WindowDestroyedEnumerator(AudioChannelAgent* aAgent,
+                            nsAutoPtr<AudioChannelAgentData>& aData,
+                            void *aPtr);
+
   // This returns the number of agents from this aWindow.
   uint32_t CountWindow(nsIDOMWindow* aWindow);
 
   nsClassHashtable< nsPtrHashKey<AudioChannelAgent>, AudioChannelAgentData > mAgents;
 #ifdef MOZ_WIDGET_GONK
   nsTArray<SpeakerManagerService*>  mSpeakerManager;
 #endif
   nsTArray<uint64_t> mChannelCounters[AUDIO_CHANNEL_INT_LAST];