Bug 1303060: Changes to a11y to enable the serving of a COM handler; r=tbsaunde
authorAaron Klotz <aklotz@mozilla.com>
Tue, 04 Apr 2017 15:23:55 -0600
changeset 351328 11457e63c6c46cb023717215251144fd5de9e827
parent 351327 7ac90be55d0c3dffc7295417d49642588d218644
child 351329 834830b0fa526106e663bba6498a9d1988c0c298
push id88841
push useraklotz@mozilla.com
push dateWed, 05 Apr 2017 16:41:19 +0000
treeherdermozilla-inbound@bfc959fb2495 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstbsaunde
bugs1303060
milestone55.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 1303060: Changes to a11y to enable the serving of a COM handler; r=tbsaunde MozReview-Commit-ID: GTQF3x1pBtX A general outline of the COM handler (a.k.a. the "smart proxy"): COM handlers are pieces of code that are loaded by the COM runtime along with a proxy and are layered above that proxy. This enables the COM handler to interpose itself between the caller and the proxy, thus providing the opportunity for the handler to manipulate an interface's method calls before those calls reach the proxy. Handlers are regular COM components that live in DLLs and are declared in the Windows registry. In order to allow for the specifying of a handler (and an optional payload to be sent with the proxy), the mscom library allows its clients to specify an implementation of the IHandlerProvider interface. IHandlerProvider consists of 5 functions: * GetHandler returns the CLSID of the component that should be loaded into the COM client's process. If GetHandler returns a failure code, then no handler is loaded. * GetHandlerPayloadSize and WriteHandlerPayload are for obtaining the payload data. These calls are made on a background thread but need to do their work on the main thread. We declare the payload struct in IDL. MIDL generates two functions, IA2Payload_Encode and IA2Payload_Decode, which are used by mscom::StructToStream to read and write that struct to and from buffers. * The a11y payload struct also includes an interface, IGeckoBackChannel, that allows the handler to communicate directly with Gecko. IGeckoBackChannel currently provides two methods: one to allow the handler to request fresh cache information, and the other to provide Gecko with its IHandlerControl interface. * MarshalAs accepts an IID that specifies the interface that is about to be proxied. We may want to send a more sophisticated proxy than the one that is requested. The desired IID is returned by this function. In the case of a11y interfaces, we should always return IAccessible2_3 if we are asked for one of its parent interfaces. This allows us to eliminate round trips to resolve more sophisticated interfaces later on. * NewInstance, which is needed to ensure that all descendent proxies are also imbued with the same handler code. The main focus of this patch is as follows: 1. Provide an implementation of the IHandlerProvider interface; 2. Populate the handler payload (ie, the cache) with data; 3. Modify CreateHolderFromAccessible to specify the HandlerPayload object; 4. Receive the IHandlerControl interface from the handler DLL and move it into the chrome process. Some more information about IHandlerControl: There is one IHandlerControl per handler DLL instance. It is the interface that we call in Gecko when we need to dispatch an event to the handler. In order to ensure that events are dispatched in the correct order, we need to dispatch those events from the chrome main thread so that they occur in sequential order with calls to NotifyWinEvent.
accessible/ipc/IPCTypes.h
accessible/ipc/win/COMPtrTypes.cpp
accessible/ipc/win/COMPtrTypes.h
accessible/ipc/win/HandlerProvider.cpp
accessible/ipc/win/HandlerProvider.h
accessible/ipc/win/handler/AccessibleHandler.h
accessible/ipc/win/handler/HandlerData.acf
accessible/ipc/win/handler/HandlerData.idl
accessible/ipc/win/moz.build
accessible/windows/msaa/AccessibleWrap.cpp
accessible/windows/msaa/AccessibleWrap.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
ipc/mscom/IHandlerProvider.h
ipc/mscom/Interceptor.cpp
ipc/mscom/MainThreadHandoff.cpp
ipc/mscom/MainThreadHandoff.h
--- a/accessible/ipc/IPCTypes.h
+++ b/accessible/ipc/IPCTypes.h
@@ -20,30 +20,33 @@
 #endif // !defined(COM_NO_WINDOWS_H)
 
 // COM headers pull in MSXML which conflicts with our own XMLDocument class.
 // This define excludes those conflicting definitions.
 #if !defined(__XMLDocument_FWD_DEFINED__)
 #define __XMLDocument_FWD_DEFINED__
 #endif // !defined(__XMLDocument_FWD_DEFINED__)
 
+#include <combaseapi.h>
+
 #include "mozilla/a11y/COMPtrTypes.h"
 
 // This define in rpcndr.h messes up our code, so we must undefine it after
 // COMPtrTypes.h has been included.
 #if defined(small)
 #undef small
 #endif // defined(small)
 
 #else
 
 namespace mozilla {
 namespace a11y {
 
 typedef uint32_t IAccessibleHolder;
+typedef uint32_t IHandlerControlHolder;
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // defined(XP_WIN) && defined(ACCESSIBILITY)
 
 #endif // mozilla_a11y_IPCTypes_h
 
--- a/accessible/ipc/win/COMPtrTypes.cpp
+++ b/accessible/ipc/win/COMPtrTypes.cpp
@@ -1,50 +1,76 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/a11y/COMPtrTypes.h"
 
+#include "Accessible2_3.h"
 #include "MainThreadUtils.h"
 #include "mozilla/a11y/Accessible.h"
+#include "mozilla/a11y/HandlerProvider.h"
 #include "mozilla/Move.h"
 #include "mozilla/mscom/MainThreadHandoff.h"
+#include "mozilla/mscom/Utils.h"
+#include "mozilla/Preferences.h"
 #include "mozilla/RefPtr.h"
+#include "nsXULAppAPI.h"
 
 using mozilla::mscom::MainThreadHandoff;
+using mozilla::mscom::ProxyUniquePtr;
 using mozilla::mscom::STAUniquePtr;
 
 namespace mozilla {
 namespace a11y {
 
 IAccessibleHolder
 CreateHolderFromAccessible(Accessible* aAccToWrap)
 {
   MOZ_ASSERT(aAccToWrap && NS_IsMainThread());
   if (!aAccToWrap) {
     return nullptr;
   }
 
-  IAccessible* rawNative = nullptr;
-  aAccToWrap->GetNativeInterface((void**)&rawNative);
-  MOZ_ASSERT(rawNative);
-  if (!rawNative) {
+  STAUniquePtr<IAccessible> iaToProxy;
+  aAccToWrap->GetNativeInterface(mscom::getter_AddRefs(iaToProxy));
+  MOZ_ASSERT(iaToProxy);
+  if (!iaToProxy) {
     return nullptr;
   }
 
-  STAUniquePtr<IAccessible> iaToProxy(rawNative);
+  static const bool useHandler =
+    Preferences::GetBool("accessibility.handler.enabled", false);
 
-  IAccessible* rawIntercepted = nullptr;
-  HRESULT hr = MainThreadHandoff::WrapInterface(Move(iaToProxy), &rawIntercepted);
+  RefPtr<HandlerProvider> payload;
+  if (useHandler) {
+    payload = new HandlerProvider(IID_IAccessible,
+                                  mscom::ToInterceptorTargetPtr(iaToProxy));
+  }
+
+  ProxyUniquePtr<IAccessible> intercepted;
+  HRESULT hr = MainThreadHandoff::WrapInterface(Move(iaToProxy), payload,
+                                                (IAccessible**) mscom::getter_AddRefs(intercepted));
   MOZ_ASSERT(SUCCEEDED(hr));
   if (FAILED(hr)) {
     return nullptr;
   }
 
-  IAccessibleHolder::COMPtrType iaIntercepted(rawIntercepted);
-  return IAccessibleHolder(Move(iaIntercepted));
+  return IAccessibleHolder(Move(intercepted));
+}
+
+IHandlerControlHolder
+CreateHolderFromHandlerControl(mscom::ProxyUniquePtr<IHandlerControl> aHandlerControl)
+{
+  MOZ_ASSERT(aHandlerControl);
+  MOZ_ASSERT(XRE_IsContentProcess());
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!aHandlerControl) {
+    return nullptr;
+  }
+
+  return IHandlerControlHolder(Move(aHandlerControl));
 }
 
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/ipc/win/COMPtrTypes.h
+++ b/accessible/ipc/win/COMPtrTypes.h
@@ -2,26 +2,32 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_COMPtrTypes_h
 #define mozilla_a11y_COMPtrTypes_h
 
+#include "mozilla/a11y/AccessibleHandler.h"
 #include "mozilla/mscom/COMPtrHolder.h"
 
 #include <oleacc.h>
 
 namespace mozilla {
 namespace a11y {
 
 typedef mozilla::mscom::COMPtrHolder<IAccessible, IID_IAccessible> IAccessibleHolder;
 
 class Accessible;
 
 IAccessibleHolder
 CreateHolderFromAccessible(Accessible* aAccToWrap);
 
+typedef mozilla::mscom::COMPtrHolder<IHandlerControl, IID_IHandlerControl> IHandlerControlHolder;
+
+IHandlerControlHolder
+CreateHolderFromHandlerControl(mscom::ProxyUniquePtr<IHandlerControl> aHandlerControl);
+
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_COMPtrTypes_h
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/win/HandlerProvider.cpp
@@ -0,0 +1,263 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#define INITGUID
+
+#include "mozilla/a11y/HandlerProvider.h"
+
+#include "Accessible2_3.h"
+#include "HandlerData.h"
+#include "HandlerData_i.c"
+#include "mozilla/Assertions.h"
+#include "mozilla/a11y/AccessibleWrap.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/Move.h"
+#include "mozilla/mscom/AgileReference.h"
+#include "mozilla/mscom/MainThreadInvoker.h"
+#include "mozilla/mscom/Ptr.h"
+#include "mozilla/mscom/StructStream.h"
+#include "mozilla/mscom/Utils.h"
+#include "nsThreadUtils.h"
+
+#include <memory.h>
+
+namespace mozilla {
+namespace a11y {
+
+HandlerProvider::HandlerProvider(REFIID aIid,
+                               mscom::InterceptorTargetPtr<IUnknown> aTarget)
+  : mRefCnt(0)
+  , mMutex("mozilla::a11y::HandlerProvider::mMutex")
+  , mTargetUnkIid(aIid)
+  , mTargetUnk(Move(aTarget))
+{
+}
+
+HRESULT
+HandlerProvider::QueryInterface(REFIID riid, void** ppv)
+{
+  if (!ppv) {
+    return E_INVALIDARG;
+  }
+
+  RefPtr<IUnknown> punk;
+
+  if (riid == IID_IUnknown || riid == IID_IGeckoBackChannel) {
+    punk = static_cast<IGeckoBackChannel*>(this);
+  }
+
+  if (!punk) {
+    return E_NOINTERFACE;
+  }
+
+  punk.forget(ppv);
+  return S_OK;
+}
+
+ULONG
+HandlerProvider::AddRef()
+{
+  return ++mRefCnt;
+}
+
+ULONG
+HandlerProvider::Release()
+{
+  ULONG result = --mRefCnt;
+  if (!result) {
+    delete this;
+  }
+  return result;
+}
+
+HRESULT
+HandlerProvider::GetHandler(NotNull<CLSID*> aHandlerClsid)
+{
+  if (!IsTargetInterfaceCacheable()) {
+    return E_NOINTERFACE;
+  }
+
+  *aHandlerClsid = CLSID_AccessibleHandler;
+  return S_OK;
+}
+
+void
+HandlerProvider::GetAndSerializePayload(const MutexAutoLock&)
+{
+  MOZ_ASSERT(mscom::IsCurrentThreadMTA());
+
+  if (mSerializer) {
+    return;
+  }
+
+  IA2Payload payload{};
+
+  if (!mscom::InvokeOnMainThread(this, &HandlerProvider::BuildIA2Data,
+                                 &payload.mData) ||
+      !payload.mData.mUniqueId) {
+    return;
+  }
+
+  // But we set mGeckoBackChannel on the current thread which resides in the
+  // MTA. This is important to ensure that COM always invokes
+  // IGeckoBackChannel methods in an MTA background thread.
+
+  RefPtr<IGeckoBackChannel> payloadRef(this);
+  // AddRef/Release pair for this reference is handled by payloadRef
+  payload.mGeckoBackChannel = this;
+
+  mSerializer = MakeUnique<mscom::StructToStream>(payload, &IA2Payload_Encode);
+
+  // Now that we have serialized payload, we should free any BSTRs that were
+  // allocated in BuildIA2Data.
+  ClearIA2Data(payload.mData);
+}
+
+HRESULT
+HandlerProvider::GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize)
+{
+  MOZ_ASSERT(mscom::IsCurrentThreadMTA());
+
+  if (!IsTargetInterfaceCacheable()) {
+    *aOutPayloadSize = mscom::StructToStream::GetEmptySize();
+    return S_OK;
+  }
+
+  MutexAutoLock lock(mMutex);
+
+  GetAndSerializePayload(lock);
+
+  if (!mSerializer) {
+    return E_FAIL;
+  }
+
+  *aOutPayloadSize = mSerializer->GetSize();
+  return S_OK;
+}
+
+void
+HandlerProvider::BuildIA2Data(IA2Data* aOutIA2Data)
+{
+  MOZ_ASSERT(aOutIA2Data);
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mTargetUnk);
+  MOZ_ASSERT(IsTargetInterfaceCacheable());
+
+  RefPtr<NEWEST_IA2_INTERFACE>
+    target(static_cast<NEWEST_IA2_INTERFACE*>(mTargetUnk.get()));
+
+  // NB: get_uniqueID should be the final property retrieved in this method,
+  // as its presence is used to determine whether the rest of this data
+  // retrieval was successful.
+  HRESULT hr = target->get_uniqueID(&aOutIA2Data->mUniqueId);
+  if (FAILED(hr)) {
+    ClearIA2Data(*aOutIA2Data);
+  }
+}
+
+void
+HandlerProvider::ClearIA2Data(IA2Data& aData)
+{
+  ZeroMemory(&aData, sizeof(IA2Data));
+}
+
+bool
+HandlerProvider::IsTargetInterfaceCacheable()
+{
+  return MarshalAs(mTargetUnkIid) == NEWEST_IA2_IID;
+}
+
+HRESULT
+HandlerProvider::WriteHandlerPayload(NotNull<IStream*> aStream)
+{
+  MutexAutoLock lock(mMutex);
+
+  if (!mSerializer) {
+    mscom::StructToStream emptyStruct;
+    return emptyStruct.Write(aStream);
+  }
+
+  HRESULT hr = mSerializer->Write(aStream);
+
+  mSerializer.reset();
+
+  return hr;
+}
+
+REFIID
+HandlerProvider::MarshalAs(REFIID aIid)
+{
+  static_assert(&NEWEST_IA2_IID == &IID_IAccessible2_3,
+                "You have modified NEWEST_IA2_IID. This code needs updating.");
+  if (aIid == IID_IDispatch || aIid == IID_IAccessible ||
+      aIid == IID_IAccessible2 || aIid == IID_IAccessible2_2 ||
+      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::NewInstance(REFIID aIid,
+                             mscom::InterceptorTargetPtr<IUnknown> aTarget,
+                             NotNull<mscom::IHandlerProvider**> aOutNewPayload)
+{
+  RefPtr<IHandlerProvider> newPayload(new HandlerProvider(aIid, Move(aTarget)));
+  newPayload.forget(aOutNewPayload.get());
+  return S_OK;
+}
+
+void
+HandlerProvider::SetHandlerControlOnMainThread(DWORD aPid,
+                                              mscom::ProxyUniquePtr<IHandlerControl> aCtrl)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto content = dom::ContentChild::GetSingleton();
+  MOZ_ASSERT(content);
+
+  IHandlerControlHolder holder(CreateHolderFromHandlerControl(Move(aCtrl)));
+  Unused << content->SendA11yHandlerControl(aPid, holder);
+}
+
+HRESULT
+HandlerProvider::put_HandlerControl(long aPid, IHandlerControl* aCtrl)
+{
+  MOZ_ASSERT(mscom::IsCurrentThreadMTA());
+
+  if (!aCtrl) {
+    return E_INVALIDARG;
+  }
+
+  auto ptrProxy = mscom::ToProxyUniquePtr(aCtrl);
+
+  if (!mscom::InvokeOnMainThread(this,
+                                 &HandlerProvider::SetHandlerControlOnMainThread,
+                                 static_cast<DWORD>(aPid), Move(ptrProxy))) {
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+HRESULT
+HandlerProvider::Refresh(IA2Data* aOutData)
+{
+  MOZ_ASSERT(mscom::IsCurrentThreadMTA());
+
+  if (!mscom::InvokeOnMainThread(this, &HandlerProvider::BuildIA2Data,
+                                 aOutData)) {
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+} // namespace a11y
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/win/HandlerProvider.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_HandlerProvider_h
+#define mozilla_a11y_HandlerProvider_h
+
+#include "handler/AccessibleHandler.h"
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/mscom/IHandlerProvider.h"
+#include "mozilla/mscom/Ptr.h"
+#include "mozilla/mscom/StructStream.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/UniquePtr.h"
+
+struct NEWEST_IA2_INTERFACE;
+
+namespace mozilla {
+
+namespace mscom {
+
+class StructToStream;
+
+} // namespace mscom
+
+namespace a11y {
+
+class HandlerProvider final : public IGeckoBackChannel
+                            , public mscom::IHandlerProvider
+{
+public:
+  HandlerProvider(REFIID aIid, mscom::InterceptorTargetPtr<IUnknown> aTarget);
+
+  // IUnknown
+  STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
+  STDMETHODIMP_(ULONG) AddRef() override;
+  STDMETHODIMP_(ULONG) Release() override;
+
+  // IHandlerProvider
+  STDMETHODIMP GetHandler(NotNull<CLSID*> aHandlerClsid) override;
+  STDMETHODIMP GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize) override;
+  STDMETHODIMP WriteHandlerPayload(NotNull<IStream*> aStream) override;
+  STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) override;
+  STDMETHODIMP NewInstance(REFIID aIid,
+                           mscom::InterceptorTargetPtr<IUnknown> aTarget,
+                           NotNull<mscom::IHandlerProvider**> aOutNewPayload) override;
+
+  // IGeckoBackChannel
+  STDMETHODIMP put_HandlerControl(long aPid, IHandlerControl* aCtrl) override;
+  STDMETHODIMP Refresh(IA2Data* aOutData) override;
+
+private:
+  ~HandlerProvider() = default;
+
+  void SetHandlerControlOnMainThread(DWORD aPid,
+                                     mscom::ProxyUniquePtr<IHandlerControl> aCtrl);
+  void GetAndSerializePayload(const MutexAutoLock&);
+  void BuildIA2Data(IA2Data* aOutIA2Data);
+  static void ClearIA2Data(IA2Data& aData);
+  bool IsTargetInterfaceCacheable();
+
+  Atomic<uint32_t>                  mRefCnt;
+  Mutex                             mMutex; // Protects mSerializer
+  REFIID                            mTargetUnkIid;
+  mscom::InterceptorTargetPtr<IUnknown> mTargetUnk; // Constant, main thread only
+  UniquePtr<mscom::StructToStream>  mSerializer;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif // mozilla_a11y_HandlerProvider_h
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/win/handler/AccessibleHandler.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_AccessibleHandler_h
+#define mozilla_a11y_AccessibleHandler_h
+
+#define NEWEST_IA2_BASENAME Accessible2_3
+
+#define __QUOTE(idl) #idl
+#define __GENIDL(base) __QUOTE(base##.idl)
+#define IDLFOR(base) __GENIDL(base)
+#define NEWEST_IA2_IDL IDLFOR(NEWEST_IA2_BASENAME)
+
+#define __GENIFACE(base) I##base
+#define INTERFACEFOR(base) __GENIFACE(base)
+#define NEWEST_IA2_INTERFACE INTERFACEFOR(NEWEST_IA2_BASENAME)
+
+#define __GENIID(iface) IID_##iface
+#define IIDFOR(iface) __GENIID(iface)
+#define NEWEST_IA2_IID IIDFOR(NEWEST_IA2_INTERFACE)
+
+#if defined(__midl)
+
+import NEWEST_IA2_IDL;
+
+#else
+
+#include "HandlerData.h"
+
+#include <windows.h>
+
+#endif // defined(__midl)
+
+#endif // mozilla_a11y_AccessibleHandler_h
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/win/handler/HandlerData.acf
@@ -0,0 +1,11 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+[explicit_handle]
+interface HandlerData
+{
+  typedef [encode,decode] IA2Payload;
+}
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/win/handler/HandlerData.idl
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AccessibleHandler.h"
+
+import "ocidl.idl";
+import "ServProv.idl";
+
+typedef struct _IA2Data
+{
+  long mUniqueId;
+} IA2Data;
+
+interface IGeckoBackChannel;
+
+// We define different CLSIDs and IIDs depending on channel and officiality.
+// This prevents handlers from installing overtop one another when multiple
+// channels are present. Note that we do not do this for all UUIDs in this IDL,
+// just the ones that are written to the registry (coclass and interfaces that
+// have the [object] annotation)
+#if !defined(MOZ_OFFICIAL_BRANDING)
+
+# if defined(DEBUG)
+
+// Local debug builds
+#  define HANDLER_CLSID 398ffd8d-5382-48f7-9e3b-19012762d39a
+#  define IHANDLERCONTROL_IID a218497e-8b10-460b-b668-a92b7ee39ff2
+#  define ASYNCIHANDLERCONTROL_IID ca18b9ab-04b6-41be-87f7-d99913d6a2e8
+#  define IGECKOBACKCHANNEL_IID 231c4946-4479-4c8e-aadc-8a0e48fc4c51
+
+# else
+
+// Local non-debug builds
+#  define HANDLER_CLSID ce573faf-7815-4fc2-a031-b092268ace9e
+#  define IHANDLERCONTROL_IID 2b715cce-1790-4fe1-aef5-48bb5acdf3a1
+#  define ASYNCIHANDLERCONTROL_IID 8e089670-4f57-41a7-89c0-37f17482fa6f
+#  define IGECKOBACKCHANNEL_IID 18e2488d-310f-400f-8339-0e50b513e801
+
+# endif
+
+#elif defined(NIGHTLY_BUILD)
+
+// Official Nightly
+# define IHANDLERCONTROL_IID c57343fc-e011-40c2-b748-da82eabf0f1f
+# define ASYNCIHANDLERCONTROL_IID 648c92a1-ea35-46da-a806-6b55c6247373
+# define HANDLER_CLSID 4629216b-8753-41bf-9527-5bff51401671
+# define IGECKOBACKCHANNEL_IID e61e038d-40dd-464a-9aba-66b206b6911b
+
+#elif defined(RELEASE_OR_BETA)
+
+// Official Beta and Official Release
+# define IHANDLERCONTROL_IID ce30f77e-8847-44f0-a648-a9656bd89c0d
+# define ASYNCIHANDLERCONTROL_IID dca8d857-1a63-4045-8f36-8809eb093d04
+# define HANDLER_CLSID 1baa303d-b4b9-45e5-9ccb-e3fca3e274b6
+# define IGECKOBACKCHANNEL_IID b32983ff-ef84-4945-8f86-fb7491b4f57b
+
+#else
+
+// Official Aurora
+# define IHANDLERCONTROL_IID 3316ce35-f892-4832-97c5-06c52c03cdba
+# define ASYNCIHANDLERCONTROL_IID 15b48b76-ad38-4ad3-bd1a-d3c48a5a9947
+# define HANDLER_CLSID 4a195748-dca2-45fb-9295-0a139e76a9e7
+# define IGECKOBACKCHANNEL_IID dd2e4a89-999e-4d65-8b65-440c923ddb61
+
+#endif
+
+[uuid(2b0e83b3-fd1a-443f-9ed6-c00d39055b58)]
+interface HandlerData
+{
+  typedef struct _IA2Payload
+  {
+    IA2Data mData;
+    IGeckoBackChannel* mGeckoBackChannel;
+  } IA2Payload;
+}
+
+[object,
+ uuid(IHANDLERCONTROL_IID),
+ async_uuid(ASYNCIHANDLERCONTROL_IID),
+ pointer_default(unique)]
+interface IHandlerControl : IUnknown
+{
+  HRESULT Invalidate();
+}
+
+[object,
+ uuid(IGECKOBACKCHANNEL_IID),
+ pointer_default(unique)]
+interface IGeckoBackChannel : IUnknown
+{
+  [propput] HRESULT HandlerControl([in] long aPid, [in] IHandlerControl* aCtrl);
+  HRESULT Refresh([out] IA2Data* aOutData);
+}
+
+[uuid(1e545f07-f108-4912-9471-546827a80983)]
+library AccessibleHandlerTypeLib
+{
+  /**
+   * This definition is required in order for the handler implementation to
+   * support IDispatch (aka Automation). This is used by interpreted language
+   * FFIs to discover which interfaces may be controlled via IDispatch.
+   * (In particular, the python FFI used by NVDA needs this).
+   *
+   * In reality, the only a11y interface that is Automation compliant is
+   * IAccessible; our remaining interfaces are not.
+   *
+   * Once the FFI knows that IAccessible is supported, the FFI queries for
+   * IAccessible and is then able to resolve non-automation interfaces from
+   * there.
+   */
+  [uuid(HANDLER_CLSID)]
+  coclass AccessibleHandler
+  {
+    [default] interface IAccessible;
+  };
+};
--- a/accessible/ipc/win/moz.build
+++ b/accessible/ipc/win/moz.build
@@ -1,32 +1,38 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 if CONFIG['COMPILE_ENVIRONMENT']:
-    DIRS += ['typelib']
+    DIRS += [
+        'handler',
+        'typelib',
+    ]
 
 # With --disable-accessibility, we need to compile PDocAccessible.ipdl (which
 # also depends on COMPtrTypes.h), but not the C++.
 IPDL_SOURCES += ['PDocAccessible.ipdl']
 EXPORTS.mozilla.a11y += ['COMPtrTypes.h']
 
 if CONFIG['ACCESSIBILITY']:
     EXPORTS.mozilla.a11y += [
         'DocAccessibleChild.h',
+        'HandlerProvider.h',
         'PlatformChild.h',
         'ProxyAccessible.h'
     ]
 
     SOURCES += [
+        '!./handler/HandlerData_c.c',
         'COMPtrTypes.cpp',
         'DocAccessibleChild.cpp',
+        'HandlerProvider.cpp',
         'PlatformChild.cpp',
         'ProxyAccessible.cpp',
     ]
 
     LOCAL_INCLUDES += [
         '/accessible/base',
         '/accessible/generic',
         '/accessible/windows/ia2',
--- a/accessible/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -57,16 +57,17 @@ const uint32_t USE_ROLE_STRING = 0;
 
 //#define DEBUG_LEAKS
 
 #ifdef DEBUG_LEAKS
 static gAccessibles = 0;
 #endif
 
 MsaaIdGenerator AccessibleWrap::sIDGen;
+StaticAutoPtr<nsTArray<AccessibleWrap::HandlerControllerData>> AccessibleWrap::sHandlerControllers;
 
 static const VARIANT kVarChildIdSelf = {VT_I4};
 
 static const int32_t kIEnumVariantDisconnected = -1;
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccessibleWrap
 ////////////////////////////////////////////////////////////////////////////////
@@ -1601,8 +1602,28 @@ AccessibleWrap::GetContentProcessIdFor(d
 }
 
 /* static */
 void
 AccessibleWrap::ReleaseContentProcessIdFor(dom::ContentParentId aIPCContentId)
 {
   sIDGen.ReleaseContentProcessIDFor(aIPCContentId);
 }
+
+/* static */
+void
+AccessibleWrap::SetHandlerControl(DWORD aPid, RefPtr<IHandlerControl> aCtrl)
+{
+  MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
+
+  if (!sHandlerControllers) {
+    sHandlerControllers = new nsTArray<HandlerControllerData>();
+    ClearOnShutdown(&sHandlerControllers);
+  }
+
+  HandlerControllerData ctrlData(aPid, Move(aCtrl));
+  if (sHandlerControllers->Contains(ctrlData)) {
+    return;
+  }
+
+  sHandlerControllers->AppendElement(Move(ctrlData));
+}
+
--- a/accessible/windows/msaa/AccessibleWrap.h
+++ b/accessible/windows/msaa/AccessibleWrap.h
@@ -9,19 +9,21 @@
 
 #include "nsCOMPtr.h"
 #include "Accessible.h"
 #include "Accessible2.h"
 #include "ia2Accessible.h"
 #include "ia2AccessibleComponent.h"
 #include "ia2AccessibleHyperlink.h"
 #include "ia2AccessibleValue.h"
+#include "mozilla/a11y/AccessibleHandler.h"
 #include "mozilla/a11y/MsaaIdGenerator.h"
 #include "mozilla/a11y/ProxyAccessible.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/mscom/Utils.h"
 
 #ifdef __GNUC__
 // Inheriting from both XPCOM and MSCOM interfaces causes a lot of warnings
 // about virtual functions being hidden by each other. This is done by
 // design, so silence the warning.
 #pragma GCC diagnostic ignored "-Woverloaded-virtual"
 #endif
 
@@ -183,16 +185,18 @@ public: // construction, destruction
 
   uint32_t GetExistingID() const { return mID; }
   static const uint32_t kNoID = 0;
   void SetID(uint32_t aID);
 
   static uint32_t GetContentProcessIdFor(dom::ContentParentId aIPCContentId);
   static void ReleaseContentProcessIdFor(dom::ContentParentId aIPCContentId);
 
+  static void SetHandlerControl(DWORD aPid, RefPtr<IHandlerControl> aCtrl);
+
 protected:
   virtual ~AccessibleWrap();
 
   uint32_t mID;
 
   HRESULT
   ResolveChild(const VARIANT& aVarChild, IAccessible** aOutInterface);
 
@@ -237,16 +241,49 @@ protected:
     NAVRELATION_CONTAINING_DOCUMENT = 0x1011,
     NAVRELATION_CONTAINING_TAB_PANE = 0x1012,
     NAVRELATION_CONTAINING_APPLICATION = 0x1014,
     NAVRELATION_DETAILS = 0x1015,
     NAVRELATION_DETAILS_FOR = 0x1016,
     NAVRELATION_ERROR = 0x1017,
     NAVRELATION_ERROR_FOR = 0x1018
   };
+
+  struct HandlerControllerData final
+  {
+    HandlerControllerData(DWORD aPid, RefPtr<IHandlerControl>&& aCtrl)
+      : mPid(aPid)
+      , mCtrl(Move(aCtrl))
+    {
+      mIsProxy = mozilla::mscom::IsProxy(mCtrl);
+    }
+
+    HandlerControllerData(HandlerControllerData&& aOther)
+      : mPid(aOther.mPid)
+      , mIsProxy(aOther.mIsProxy)
+      , mCtrl(Move(aOther.mCtrl))
+    {
+    }
+
+    bool operator==(const HandlerControllerData& aOther) const
+    {
+      return mPid == aOther.mPid;
+    }
+
+    bool operator==(const DWORD& aPid) const
+    {
+      return mPid == aPid;
+    }
+
+    DWORD mPid;
+    bool mIsProxy;
+    RefPtr<IHandlerControl> mCtrl;
+  };
+
+  static StaticAutoPtr<nsTArray<HandlerControllerData>> sHandlerControllers;
 };
 
 static inline AccessibleWrap*
 WrapperFor(const ProxyAccessible* aProxy)
 {
   return reinterpret_cast<AccessibleWrap*>(aProxy->GetWrapper());
 }
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -167,16 +167,19 @@
 #endif
 
 #ifdef MOZ_X11
 #include "mozilla/X11Util.h"
 #endif
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
+#ifdef XP_WIN
+#include "mozilla/a11y/AccessibleWrap.h"
+#endif
 #endif
 
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/PPresentationChild.h"
 #include "mozilla/dom/PresentationIPCService.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 
 #ifdef MOZ_WEBSPEECH
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -4920,16 +4920,30 @@ ContentParent::RecvGetA11yContentId(uint
   *aContentId = a11y::AccessibleWrap::GetContentProcessIdFor(ChildID());
   MOZ_ASSERT(*aContentId);
   return IPC_OK();
 #else
   return IPC_FAIL_NO_REASON(this);
 #endif
 }
 
+mozilla::ipc::IPCResult
+ContentParent::RecvA11yHandlerControl(const uint32_t& aPid,
+                                      const IHandlerControlHolder& aHandlerControl)
+{
+#if defined(XP_WIN32) && defined(ACCESSIBILITY)
+  MOZ_ASSERT(!aHandlerControl.IsNull());
+  RefPtr<IHandlerControl> proxy(aHandlerControl.Get());
+  a11y::AccessibleWrap::SetHandlerControl(aPid, Move(proxy));
+  return IPC_OK();
+#else
+  return IPC_FAIL_NO_REASON(this);
+#endif
+}
+
 } // namespace dom
 } // namespace mozilla
 
 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
 
 NS_IMETHODIMP
 ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData)
 {
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -594,16 +594,20 @@ public:
                                   const nsString& aOldValue,
                                   const nsString& aNewValue,
                                   const IPC::Principal& aPrincipal,
                                   const bool& aIsPrivate) override;
 
   virtual mozilla::ipc::IPCResult
   RecvGetA11yContentId(uint32_t* aContentId) override;
 
+  virtual mozilla::ipc::IPCResult
+  RecvA11yHandlerControl(const uint32_t& aPid,
+                         const IHandlerControlHolder& aHandlerControl) override;
+
   virtual int32_t Pid() const override;
 
   virtual PURLClassifierParent*
   AllocPURLClassifierParent(const Principal& aPrincipal,
                             const bool& aUseTrackingProtection,
                             bool* aSuccess) override;
   virtual mozilla::ipc::IPCResult
   RecvPURLClassifierConstructor(PURLClassifierParent* aActor,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -68,16 +68,17 @@ using AlertNotificationType from "mozill
 using struct ChromePackage from "mozilla/chrome/RegistryMessageUtils.h";
 using struct SubstitutionMapping from "mozilla/chrome/RegistryMessageUtils.h";
 using struct OverrideMapping from "mozilla/chrome/RegistryMessageUtils.h";
 using base::ChildPrivileges from "base/process_util.h";
 using base::ProcessId from "base/process.h";
 using struct IPC::Permission from "mozilla/net/NeckoMessageUtils.h";
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
+using mozilla::a11y::IHandlerControlHolder from "mozilla/a11y/IPCTypes.h";
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
 using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
 using mozilla::LayoutDeviceIntPoint from "Units.h";
 using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
 using class mozilla::dom::MessagePort from "mozilla/dom/MessagePort.h";
@@ -1078,16 +1079,18 @@ parent:
      */
     async AccumulateChildHistograms(Accumulation[] accumulations);
     async AccumulateChildKeyedHistograms(KeyedAccumulation[] accumulations);
     async UpdateChildScalars(ScalarAction[] updates);
     async UpdateChildKeyedScalars(KeyedScalarAction[] updates);
     async RecordChildEvents(ChildEventData[] events);
 
     sync GetA11yContentId() returns (uint32_t aContentId);
+    async A11yHandlerControl(uint32_t aPid,
+                             IHandlerControlHolder aHandlerControl);
 
     async AddMemoryReport(MemoryReport aReport);
     async FinishMemoryReport(uint32_t aGeneration);
 
 both:
      async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
                         Principal aPrincipal, ClonedMessageData aData);
 
--- a/ipc/mscom/IHandlerProvider.h
+++ b/ipc/mscom/IHandlerProvider.h
@@ -2,35 +2,36 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_mscom_IHandlerProvider_h
 #define mozilla_mscom_IHandlerProvider_h
 
+#include "mozilla/NotNull.h"
 #include "mozilla/mscom/Ptr.h"
 
 #include <objidl.h>
 
 namespace mozilla {
 namespace mscom {
 
 struct HandlerProvider
 {
-  virtual STDMETHODIMP GetHandler(CLSID* aHandlerClsid) = 0;
-  virtual STDMETHODIMP GetHandlerPayloadSize(DWORD* aOutPayloadSize) = 0;
-  virtual STDMETHODIMP WriteHandlerPayload(IStream* aStream) = 0;
+  virtual STDMETHODIMP GetHandler(NotNull<CLSID*> aHandlerClsid) = 0;
+  virtual STDMETHODIMP GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize) = 0;
+  virtual STDMETHODIMP WriteHandlerPayload(NotNull<IStream*> aStream) = 0;
   virtual STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) = 0;
 };
 
 struct IHandlerProvider : public IUnknown
                         , public HandlerProvider
 {
   virtual STDMETHODIMP NewInstance(REFIID aIid,
                                    InterceptorTargetPtr<IUnknown> aTarget,
-                                   IHandlerProvider** aOutNewPayload) = 0;
+                                   NotNull<IHandlerProvider**> aOutNewPayload) = 0;
 };
 
 } // namespace mscom
 } // namespace mozilla
 
 #endif // mozilla_mscom_IHandlerProvider_h
--- a/ipc/mscom/Interceptor.cpp
+++ b/ipc/mscom/Interceptor.cpp
@@ -73,17 +73,17 @@ HRESULT
 Interceptor::GetClassForHandler(DWORD aDestContext, void* aDestContextPtr,
                                 CLSID* aHandlerClsid)
 {
   if (aDestContextPtr || !aHandlerClsid ||
       aDestContext == MSHCTX_DIFFERENTMACHINE) {
     return E_INVALIDARG;
   }
   MOZ_ASSERT(mEventSink);
-  return mEventSink->GetHandler(aHandlerClsid);
+  return mEventSink->GetHandler(WrapNotNull(aHandlerClsid));
 }
 
 HRESULT
 Interceptor::GetUnmarshalClass(REFIID riid, void* pv, DWORD dwDestContext,
                                void* pvDestContext, DWORD mshlflags,
                                CLSID* pCid)
 {
   return mStdMarshal->GetUnmarshalClass(riid, pv, dwDestContext, pvDestContext,
@@ -97,33 +97,33 @@ Interceptor::GetMarshalSizeMax(REFIID ri
 {
   HRESULT hr = mStdMarshal->GetMarshalSizeMax(riid, pv, dwDestContext,
                                               pvDestContext, mshlflags, pSize);
   if (FAILED(hr)) {
     return hr;
   }
 
   DWORD payloadSize = 0;
-  hr = mEventSink->GetHandlerPayloadSize(&payloadSize);
+  hr = mEventSink->GetHandlerPayloadSize(WrapNotNull(&payloadSize));
   *pSize += payloadSize;
   return hr;
 }
 
 HRESULT
 Interceptor::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
                               DWORD dwDestContext, void* pvDestContext,
                               DWORD mshlflags)
 {
   HRESULT hr = mStdMarshal->MarshalInterface(pStm, riid, pv, dwDestContext,
                                              pvDestContext, mshlflags);
   if (FAILED(hr)) {
     return hr;
   }
 
-  return mEventSink->WriteHandlerPayload(pStm);
+  return mEventSink->WriteHandlerPayload(WrapNotNull(pStm));
 }
 
 HRESULT
 Interceptor::UnmarshalInterface(IStream* pStm, REFIID riid,
                                 void** ppv)
 {
   return mStdMarshal->UnmarshalInterface(pStm, riid, ppv);
 }
@@ -359,31 +359,31 @@ Interceptor::ThreadSafeQueryInterface(RE
     return E_NOINTERFACE;
   }
 
   if (aIid == IID_IStdMarshalInfo) {
     // Do not indicate that this interface is available unless we actually
     // support it. We'll check that by looking for a successful call to
     // IInterceptorSink::GetHandler()
     CLSID dummy;
-    if (FAILED(mEventSink->GetHandler(&dummy))) {
+    if (FAILED(mEventSink->GetHandler(WrapNotNull(&dummy)))) {
       return E_NOINTERFACE;
     }
 
     RefPtr<IStdMarshalInfo> std(this);
     std.forget(aOutInterface);
     return S_OK;
   }
 
   if (aIid == IID_IMarshal) {
     // Do not indicate that this interface is available unless we actually
     // support it. We'll check that by looking for a successful call to
     // IInterceptorSink::GetHandler()
     CLSID dummy;
-    if (FAILED(mEventSink->GetHandler(&dummy))) {
+    if (FAILED(mEventSink->GetHandler(WrapNotNull(&dummy)))) {
       return E_NOINTERFACE;
     }
 
     if (!mStdMarshalUnk) {
       HRESULT hr = ::CoGetStdMarshalEx(static_cast<IWeakReferenceSource*>(this),
                                        SMEXF_SERVER,
                                        getter_AddRefs(mStdMarshalUnk));
       if (FAILED(hr)) {
--- a/ipc/mscom/MainThreadHandoff.cpp
+++ b/ipc/mscom/MainThreadHandoff.cpp
@@ -443,35 +443,35 @@ MainThreadHandoff::FixArrayElements(ICal
 HRESULT
 MainThreadHandoff::SetInterceptor(IWeakReference* aInterceptor)
 {
   mInterceptor = aInterceptor;
   return S_OK;
 }
 
 HRESULT
-MainThreadHandoff::GetHandler(CLSID* aHandlerClsid)
+MainThreadHandoff::GetHandler(NotNull<CLSID*> aHandlerClsid)
 {
   if (!mHandlerProvider) {
     return E_NOTIMPL;
   }
   return mHandlerProvider->GetHandler(aHandlerClsid);
 }
 
 HRESULT
-MainThreadHandoff::GetHandlerPayloadSize(DWORD* aOutPayloadSize)
+MainThreadHandoff::GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize)
 {
   if (!mHandlerProvider) {
     return E_NOTIMPL;
   }
   return mHandlerProvider->GetHandlerPayloadSize(aOutPayloadSize);
 }
 
 HRESULT
-MainThreadHandoff::WriteHandlerPayload(IStream* aStream)
+MainThreadHandoff::WriteHandlerPayload(NotNull<IStream*> aStream)
 {
   if (!mHandlerProvider) {
     return E_NOTIMPL;
   }
   return mHandlerProvider->WriteHandlerPayload(aStream);
 }
 
 REFIID
@@ -562,17 +562,17 @@ MainThreadHandoff::OnWalkInterface(REFII
       return S_OK;
     }
   }
 
   RefPtr<IHandlerProvider> payload;
   if (mHandlerProvider) {
     hr = mHandlerProvider->NewInstance(aIid,
                                        ToInterceptorTargetPtr(origInterface),
-                                       getter_AddRefs(payload));
+                                       WrapNotNull((IHandlerProvider**)getter_AddRefs(payload)));
     MOZ_ASSERT(SUCCEEDED(hr));
     if (FAILED(hr)) {
       return hr;
     }
   }
 
   // Now create a new MainThreadHandoff wrapper...
   RefPtr<IInterceptorSink> handoff;
--- a/ipc/mscom/MainThreadHandoff.h
+++ b/ipc/mscom/MainThreadHandoff.h
@@ -55,19 +55,19 @@ public:
   STDMETHODIMP_(ULONG) AddRef() override;
   STDMETHODIMP_(ULONG) Release() override;
 
   // ICallFrameEvents
   STDMETHODIMP OnCall(ICallFrame* aFrame) override;
 
   // IInterceptorSink
   STDMETHODIMP SetInterceptor(IWeakReference* aInterceptor) override;
-  STDMETHODIMP GetHandler(CLSID* aHandlerClsid) override;
-  STDMETHODIMP GetHandlerPayloadSize(DWORD* aOutPayloadSize) override;
-  STDMETHODIMP WriteHandlerPayload(IStream* aStream) override;
+  STDMETHODIMP GetHandler(NotNull<CLSID*> aHandlerClsid) override;
+  STDMETHODIMP GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize) override;
+  STDMETHODIMP WriteHandlerPayload(NotNull<IStream*> aStream) override;
   STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) override;
 
   // ICallFrameWalker
   STDMETHODIMP OnWalkInterface(REFIID aIid, PVOID* aInterface, BOOL aIsInParam,
                                BOOL aIsOutParam) override;
 
 private:
   explicit MainThreadHandoff(IHandlerProvider* aHandlerProvider);