Bug 1434822 part 3: On Windows, when a content Accessible shuts down, disconnect all associated remote clients. r?MarcoZ
To improve performance for cross-process COM, we disable COM garbage collection.
However, this means we never receive Release calls from clients, so defunct accessibles can never be deleted.
Since we know when an accessible is shutting down, we can work around this by forcing COM to disconnect this object from all of its remote clients, which will cause associated references to be released.
MozReview-Commit-ID: 5sIuxnaRJWj
--- a/accessible/ipc/win/HandlerProvider.cpp
+++ b/accessible/ipc/win/HandlerProvider.cpp
@@ -459,16 +459,23 @@ HandlerProvider::MarshalAs(REFIID aIid)
aIid == IID_IAccessible2_3) {
// This should always be the newest IA2 interface ID
return NEWEST_IA2_IID;
}
// Otherwise we juse return the identity.
return aIid;
}
+HRESULT
+HandlerProvider::DisconnectHandlerRemotes()
+{
+ IUnknown* unk = static_cast<IGeckoBackChannel*>(this);
+ return ::CoDisconnectObject(unk, 0);
+}
+
REFIID
HandlerProvider::GetEffectiveOutParamIid(REFIID aCallIid,
ULONG aCallMethod)
{
if (aCallIid == IID_IAccessibleTable ||
aCallIid == IID_IAccessibleTable2 ||
aCallIid == IID_IAccessibleDocument ||
aCallIid == IID_IAccessibleTableCell ||
--- a/accessible/ipc/win/HandlerProvider.h
+++ b/accessible/ipc/win/HandlerProvider.h
@@ -42,16 +42,17 @@ public:
// IHandlerProvider
STDMETHODIMP GetHandler(NotNull<CLSID*> aHandlerClsid) override;
STDMETHODIMP GetHandlerPayloadSize(NotNull<mscom::IInterceptor*> aInterceptor,
NotNull<DWORD*> aOutPayloadSize) override;
STDMETHODIMP WriteHandlerPayload(NotNull<mscom::IInterceptor*> aInterceptor,
NotNull<IStream*> aStream) override;
STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) override;
+ STDMETHODIMP DisconnectHandlerRemotes() override;
STDMETHODIMP_(REFIID) GetEffectiveOutParamIid(REFIID aCallIid,
ULONG aCallMethod) override;
STDMETHODIMP NewInstance(REFIID aIid,
mscom::InterceptorTargetPtr<IUnknown> aTarget,
NotNull<mscom::IHandlerProvider**> aOutNewPayload) override;
// IGeckoBackChannel
STDMETHODIMP put_HandlerControl(long aPid, IHandlerControl* aCtrl) override;
--- a/accessible/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -41,16 +41,17 @@
#include "nsView.h"
#include "nsViewManager.h"
#include "nsEventMap.h"
#include "nsArrayUtils.h"
#include "mozilla/Preferences.h"
#include "mozilla/ReverseIterator.h"
#include "nsIXULRuntime.h"
#include "mozilla/mscom/AsyncInvoker.h"
+#include "mozilla/mscom/Interceptor.h"
#include "oleacc.h"
using namespace mozilla;
using namespace mozilla::a11y;
const uint32_t USE_ROLE_STRING = 0;
@@ -98,16 +99,34 @@ AccessibleWrap::Shutdown()
auto doc = static_cast<DocAccessibleWrap*>(mDoc.get());
MOZ_ASSERT(doc);
if (doc) {
doc->RemoveID(mID);
mID = kNoID;
}
}
+ if (XRE_IsContentProcess()) {
+ // Bug 1434822: To improve performance for cross-process COM, we disable COM
+ // garbage collection. However, this means we never receive Release calls
+ // from clients, so defunct accessibles can never be deleted. Since we
+ // know when an accessible is shutting down, we can work around this by
+ // forcing COM to disconnect this object from all of its remote clients,
+ // which will cause associated references to be released.
+ IUnknown* unk = static_cast<IAccessible*>(this);
+ mscom::Interceptor::DisconnectRemotesForTarget(unk);
+ // If an accessible was retrieved via IAccessibleHypertext::hyperlink*,
+ // it will have a different Interceptor that won't be matched by the above
+ // call, even though it's the same object. Therefore, call it again with
+ // the IAccessibleHyperlink pointer. We can remove this horrible hack once
+ // bug 1440267 is fixed.
+ unk = static_cast<IAccessibleHyperlink*>(this);
+ mscom::Interceptor::DisconnectRemotesForTarget(unk);
+ }
+
Accessible::Shutdown();
}
//-----------------------------------------------------
// IUnknown interface methods - see iunknown.h for documentation
//-----------------------------------------------------
// Microsoft COM QueryInterface