Bug 824919: Weaken key references to PeerConnection and friends r=jesup,smaug,ekr

This commit is contained in:
Adam Roach [:abr] 2013-01-17 17:11:14 -06:00
parent e514da1eed
commit 9c2697eb77
6 changed files with 130 additions and 53 deletions

View File

@ -56,13 +56,23 @@ GlobalPCList.prototype = {
addPC: function(pc) {
let winID = pc._winID;
if (this._list[winID]) {
this._list[winID].push(pc);
this._list[winID].push(Components.utils.getWeakReference(pc));
} else {
this._list[winID] = [pc];
this._list[winID] = [Components.utils.getWeakReference(pc)];
}
this.removeNullRefs(winID);
},
removeNullRefs: function(winID) {
if (this._list === undefined || this._list[winID] === undefined) {
return;
}
this._list[winID] = this._list[winID].filter(
function (e,i,a) { return e.get() !== null; });
},
hasActivePeerConnection: function(winID) {
this.removeNullRefs(winID);
return this._list[winID] ? true : false;
},
@ -70,10 +80,13 @@ GlobalPCList.prototype = {
if (topic == "inner-window-destroyed") {
let winID = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
if (this._list[winID]) {
this._list[winID].forEach(function(pc) {
pc._pc.close(false);
delete pc._observer;
pc._pc = null;
this._list[winID].forEach(function(pcref) {
let pc = pcref.get();
if (pc !== null) {
pc._pc.close(false);
delete pc._observer;
pc._pc = null;
}
});
delete this._list[winID];
}
@ -85,10 +98,13 @@ GlobalPCList.prototype = {
// while offline, but attempts to connect them should fail.
let array;
while ((array = this._list.pop()) != undefined) {
array.forEach(function(pc) {
pc._pc.close(true);
delete pc._observer;
pc._pc = null;
array.forEach(function(pcref) {
let pc = pcref.get();
if (pc !== null) {
pc._pc.close(true);
delete pc._observer;
pc._pc = null;
}
});
};
this._networkdown = true;
@ -230,7 +246,9 @@ PeerConnection.prototype = {
flags: Ci.nsIClassInfo.DOM_OBJECT}),
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIDOMRTCPeerConnection, Ci.nsIDOMGlobalObjectConstructor
Ci.nsIDOMRTCPeerConnection,
Ci.nsIDOMGlobalObjectConstructor,
Ci.nsISupportsWeakReference
]),
// Constructor is an explicit function, because of nsIDOMGlobalObjectConstructor.
@ -538,7 +556,8 @@ function PeerConnectionObserver(dompc) {
this._dompc = dompc;
}
PeerConnectionObserver.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.IPeerConnectionObserver]),
QueryInterface: XPCOMUtils.generateQI([Ci.IPeerConnectionObserver,
Ci.nsISupportsWeakReference]),
onCreateOfferSuccess: function(offer) {
if (this._dompc._onCreateOfferSuccess) {

View File

@ -41,10 +41,14 @@ public:
if (!observerService)
return;
nsresult rv = observerService->AddObserver(this,
NS_XPCOM_SHUTDOWN_OBSERVER_ID,
false);
MOZ_ASSERT(rv == NS_OK);
nsresult rv = NS_OK;
#ifdef MOZILLA_INTERNAL_API
rv = observerService->AddObserver(this,
NS_XPCOM_SHUTDOWN_OBSERVER_ID,
false);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
#endif
(void) rv;
}

View File

@ -227,7 +227,9 @@ PeerConnectionImpl::PeerConnectionImpl()
, mIdentity(NULL)
, mSTSThread(NULL)
, mMedia(new PeerConnectionMedia(this)) {
#ifdef MOZILLA_INTERNAL_API
MOZ_ASSERT(NS_IsMainThread());
#endif
}
PeerConnectionImpl::~PeerConnectionImpl()
@ -293,10 +295,13 @@ NS_IMETHODIMP
PeerConnectionImpl::Initialize(IPeerConnectionObserver* aObserver,
nsIDOMWindow* aWindow,
nsIThread* aThread) {
#ifdef MOZILLA_INTERNAL_API
MOZ_ASSERT(NS_IsMainThread());
#endif
MOZ_ASSERT(aObserver);
MOZ_ASSERT(aThread);
mPCObserver = aObserver;
mPCObserver = do_GetWeakReference(aObserver);
nsresult res;
@ -526,8 +531,12 @@ PeerConnectionImpl::NotifyConnection()
CSFLogDebugS(logTag, __FUNCTION__);
#ifdef MOZILLA_INTERNAL_API
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return;
}
RUN_ON_THREAD(mThread,
WrapRunnable(mPCObserver,
WrapRunnable(pco,
&IPeerConnectionObserver::NotifyConnection),
NS_DISPATCH_NORMAL);
#endif
@ -541,10 +550,13 @@ PeerConnectionImpl::NotifyClosedConnection()
CSFLogDebugS(logTag, __FUNCTION__);
#ifdef MOZILLA_INTERNAL_API
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return;
}
RUN_ON_THREAD(mThread,
WrapRunnable(mPCObserver,
&IPeerConnectionObserver::NotifyClosedConnection),
NS_DISPATCH_NORMAL);
WrapRunnable(pco, &IPeerConnectionObserver::NotifyClosedConnection),
NS_DISPATCH_NORMAL);
#endif
}
@ -570,15 +582,20 @@ PeerConnectionImpl::NotifyDataChannel(already_AddRefed<mozilla::DataChannel> aCh
CSFLogDebugS(logTag, __FUNCTION__ << ": channel: " << static_cast<void*>(aChannel.get()));
#ifdef MOZILLA_INTERNAL_API
nsCOMPtr<nsIDOMDataChannel> domchannel;
nsresult rv = NS_NewDOMDataChannel(aChannel, mWindow,
getter_AddRefs(domchannel));
nsCOMPtr<nsIDOMDataChannel> domchannel;
nsresult rv = NS_NewDOMDataChannel(aChannel, mWindow,
getter_AddRefs(domchannel));
NS_ENSURE_SUCCESS_VOID(rv);
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return;
}
RUN_ON_THREAD(mThread,
WrapRunnableNM(NotifyDataChannel_m,
domchannel.get(),
mPCObserver),
pco),
NS_DISPATCH_NORMAL);
#endif
}
@ -1012,16 +1029,20 @@ PeerConnectionImpl::onCallEvent(ccapi_call_event_e aCallEvent,
break;
}
if (mPCObserver) {
PeerConnectionObserverDispatch* runnable =
new PeerConnectionObserverDispatch(aInfo, this, mPCObserver);
if (mThread) {
mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
return;
}
runnable->Run();
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return;
}
PeerConnectionObserverDispatch* runnable =
new PeerConnectionObserverDispatch(aInfo, this, pco);
if (mThread) {
mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
return;
}
runnable->Run();
delete runnable;
}
void
@ -1032,7 +1053,11 @@ PeerConnectionImpl::ChangeReadyState(PeerConnectionImpl::ReadyState aReadyState)
// Note that we are passing an nsRefPtr<IPeerConnectionObserver> which
// keeps the observer live.
RUN_ON_THREAD(mThread, WrapRunnable(mPCObserver,
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return;
}
RUN_ON_THREAD(mThread, WrapRunnable(pco,
&IPeerConnectionObserver::OnStateChange,
// static_cast needed to work around old Android NDK r5c compiler
static_cast<int>(IPeerConnectionObserver::kReadyState)),
@ -1086,14 +1111,16 @@ PeerConnectionImpl::IceGatheringCompleted_m(NrIceCtx *aCtx)
mIceState = kIceWaiting;
#ifdef MOZILLA_INTERNAL_API
if (mPCObserver) {
RUN_ON_THREAD(mThread,
WrapRunnable(mPCObserver,
&IPeerConnectionObserver::OnStateChange,
// static_cast required to work around old C++ compiler on Android NDK r5c
static_cast<int>(IPeerConnectionObserver::kIceState)),
NS_DISPATCH_NORMAL);
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return NS_OK;
}
RUN_ON_THREAD(mThread,
WrapRunnable(pco,
&IPeerConnectionObserver::OnStateChange,
// static_cast required to work around old C++ compiler on Android NDK r5c
static_cast<int>(IPeerConnectionObserver::kIceState)),
NS_DISPATCH_NORMAL);
#endif
return NS_OK;
}
@ -1121,14 +1148,16 @@ PeerConnectionImpl::IceCompleted_m(NrIceCtx *aCtx)
mIceState = kIceConnected;
#ifdef MOZILLA_INTERNAL_API
if (mPCObserver) {
RUN_ON_THREAD(mThread,
WrapRunnable(mPCObserver,
&IPeerConnectionObserver::OnStateChange,
// static_cast required to work around old C++ compiler on Android NDK r5c
static_cast<int>(IPeerConnectionObserver::kIceState)),
NS_DISPATCH_NORMAL);
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return NS_OK;
}
RUN_ON_THREAD(mThread,
WrapRunnable(pco,
&IPeerConnectionObserver::OnStateChange,
// static_cast required to work around old C++ compiler on Android NDK r5c
static_cast<int>(IPeerConnectionObserver::kIceState)),
NS_DISPATCH_NORMAL);
#endif
return NS_OK;
}

View File

@ -12,6 +12,8 @@
#include "prlock.h"
#include "mozilla/RefPtr.h"
#include "nsWeakPtr.h"
#include "nsIWeakReferenceUtils.h" // for the definition of nsWeakPtr
#include "IPeerConnection.h"
#include "nsComponentManagerUtils.h"
#include "nsPIDOMWindow.h"
@ -230,7 +232,9 @@ private:
IceState mIceState;
nsCOMPtr<nsIThread> mThread;
nsCOMPtr<IPeerConnectionObserver> mPCObserver;
// Weak pointer to IPeerConnectionObserver
// This is only safe to use on the main thread
nsWeakPtr mPCObserver;
nsCOMPtr<nsPIDOMWindow> mWindow;
// The SDP sent in from JS - here for debugging.

View File

@ -133,6 +133,7 @@ LOCAL_INCLUDES += \
-I$(topsrcdir)/media/webrtc/signaling/src/peerconnection \
-I$(topsrcdir)/media/webrtc/signaling/media-conduit\
-I$(topsrcdir)/media/webrtc/trunk/third_party/libjingle/source/ \
-I$(topsrcdir)/xpcom/base/ \
$(NULL)
ifneq ($(OS_TARGET),WINNT)

View File

@ -23,9 +23,11 @@ using namespace std;
#include "FakeMediaStreams.h"
#include "FakeMediaStreamsImpl.h"
#include "PeerConnectionImpl.h"
#include "PeerConnectionCtx.h"
#include "runnable_utils.h"
#include "nsStaticComponents.h"
#include "nsIDOMRTCPeerConnection.h"
#include "nsWeakReference.h"
#include "mtransport_test_utils.h"
MtransportTestUtils *test_utils;
@ -118,7 +120,8 @@ enum offerAnswerFlags
};
class TestObserver : public IPeerConnectionObserver
class TestObserver : public IPeerConnectionObserver,
public nsSupportsWeakReference
{
public:
enum Action {
@ -163,7 +166,9 @@ private:
std::vector<nsDOMMediaStream *> streams;
};
NS_IMPL_THREADSAFE_ISUPPORTS1(TestObserver, IPeerConnectionObserver)
NS_IMPL_THREADSAFE_ISUPPORTS2(TestObserver,
IPeerConnectionObserver,
nsISupportsWeakReference)
NS_IMETHODIMP
TestObserver::OnCreateOfferSuccess(const char* offer)
@ -489,7 +494,7 @@ class SignalingAgent {
NS_DISPATCH_SYNC);
}
void Init(nsCOMPtr<nsIThread> thread)
void Init_m(nsCOMPtr<nsIThread> thread)
{
size_t found = 2;
ASSERT_TRUE(found > 0);
@ -502,6 +507,14 @@ class SignalingAgent {
ASSERT_EQ(pc->Initialize(pObserver, nullptr, thread), NS_OK);
}
void Init(nsCOMPtr<nsIThread> thread)
{
thread->Dispatch(
WrapRunnable(this, &SignalingAgent::Init_m, thread),
NS_DISPATCH_SYNC);
ASSERT_TRUE_WAIT(sipcc_state() == sipcc::PeerConnectionImpl::kStarted,
kDefaultTimeout);
ASSERT_TRUE_WAIT(ice_state() == sipcc::PeerConnectionImpl::kIceWaiting, 5000);
@ -1808,6 +1821,13 @@ int main(int argc, char **argv) {
::testing::AddGlobalTestEnvironment(new test::SignalingEnvironment);
int result = RUN_ALL_TESTS();
// Because we don't initialize on the main thread, we can't register for
// XPCOM shutdown callbacks (where the context is usually shut down) --
// so we need to explictly destroy the context.
sipcc::PeerConnectionCtx::Destroy();
delete test_utils;
return result;
}