Bug 1133351: Backed out 0cc8abe4e2bb for assertion failures; r=bustage
authorAaron Klotz <aklotz@mozilla.com>
Sat, 28 Mar 2015 06:08:26 -0700
changeset 265168 e9769c80ee593c9981cb00079801ae040ba55213
parent 265167 b08b0a413b329ec04a9450221825496367b888fd
child 265218 73fbc0f8d061d433fd1795a19876b7039f84c3f2
child 265238 879aacc06222d7be03d60ff5ca321cf2e148558c
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbustage
bugs1133351
milestone39.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 1133351: Backed out 0cc8abe4e2bb for assertion failures; r=bustage
dom/plugins/ipc/COMMessageFilter.cpp
dom/plugins/ipc/COMMessageFilter.h
dom/plugins/ipc/PluginModuleChild.cpp
dom/plugins/ipc/moz.build
ipc/glue/WindowsMessageLoop.cpp
widget/windows/nsWindow.cpp
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ipc/COMMessageFilter.cpp
@@ -0,0 +1,84 @@
+/* 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 "base/basictypes.h"
+
+#include "COMMessageFilter.h"
+#include "base/message_loop.h"
+#include "mozilla/plugins/PluginModuleChild.h"
+
+#include <stdio.h>
+
+namespace mozilla {
+namespace plugins {
+
+HRESULT
+COMMessageFilter::QueryInterface(REFIID riid, void** ppv)
+{
+  if (riid == IID_IUnknown || riid == IID_IMessageFilter) {
+    *ppv = static_cast<IMessageFilter*>(this);
+    AddRef();
+    return S_OK;
+  }
+  return E_NOINTERFACE;
+}
+
+DWORD COMMessageFilter::AddRef()
+{
+  ++mRefCnt;
+  return mRefCnt;
+}
+
+DWORD COMMessageFilter::Release()
+{
+  DWORD r = --mRefCnt;
+  if (0 == r)
+    delete this;
+  return r;
+}
+
+DWORD 
+COMMessageFilter::HandleInComingCall(DWORD dwCallType,
+				     HTASK htaskCaller,
+				     DWORD dwTickCount,
+				     LPINTERFACEINFO lpInterfaceInfo)
+{
+  if (mPreviousFilter)
+    return mPreviousFilter->HandleInComingCall(dwCallType, htaskCaller,
+					       dwTickCount, lpInterfaceInfo);
+  return SERVERCALL_ISHANDLED;
+}
+
+DWORD
+COMMessageFilter::RetryRejectedCall(HTASK htaskCallee,
+				    DWORD dwTickCount,
+				    DWORD dwRejectType)
+{
+  if (mPreviousFilter)
+    return mPreviousFilter->RetryRejectedCall(htaskCallee, dwTickCount,
+					      dwRejectType);
+  return -1;
+}
+
+DWORD
+COMMessageFilter::MessagePending(HTASK htaskCallee,
+				 DWORD dwTickCount,
+				 DWORD dwPendingType)
+{
+  mPlugin->FlushPendingInterruptQueue();
+  if (mPreviousFilter)
+    return mPreviousFilter->MessagePending(htaskCallee, dwTickCount,
+					   dwPendingType);
+  return PENDINGMSG_WAITNOPROCESS;
+}
+
+void
+COMMessageFilter::Initialize(PluginModuleChild* module)
+{
+  nsRefPtr<COMMessageFilter> f = new COMMessageFilter(module);
+  ::CoRegisterMessageFilter(f, getter_AddRefs(f->mPreviousFilter));
+}
+
+} // namespace plugins
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ipc/COMMessageFilter.h
@@ -0,0 +1,50 @@
+/* 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_plugins_COMMessageFilter_h
+#define mozilla_plugins_COMMessageFilter_h
+
+#include <objidl.h>
+#include "nsISupportsImpl.h"
+#include "nsAutoPtr.h"
+
+namespace mozilla {
+namespace plugins {
+
+class PluginModuleChild;
+
+class COMMessageFilter final : public IMessageFilter
+{
+public:
+  static void Initialize(PluginModuleChild* plugin);
+
+  COMMessageFilter(PluginModuleChild* plugin)
+    : mPlugin(plugin)
+  { }
+
+  HRESULT WINAPI QueryInterface(REFIID riid, void** ppv);
+  DWORD WINAPI AddRef();
+  DWORD WINAPI Release();
+
+  DWORD WINAPI HandleInComingCall(DWORD dwCallType,
+                                  HTASK htaskCaller,
+                                  DWORD dwTickCount,
+                                  LPINTERFACEINFO lpInterfaceInfo);
+  DWORD WINAPI RetryRejectedCall(HTASK htaskCallee,
+                                 DWORD dwTickCount,
+                                 DWORD dwRejectType);
+  DWORD WINAPI MessagePending(HTASK htaskCallee,
+                              DWORD dwTickCount,
+                              DWORD dwPendingType);
+
+private:
+  nsAutoRefCnt mRefCnt;
+  PluginModuleChild* mPlugin;
+  nsRefPtr<IMessageFilter> mPreviousFilter;
+};
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif // COMMessageFilter_h
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -37,16 +37,17 @@
 #include "mozilla/plugins/StreamNotifyChild.h"
 #include "mozilla/plugins/BrowserStreamChild.h"
 #include "mozilla/plugins/PluginStreamChild.h"
 #include "mozilla/dom/CrashReporterChild.h"
 
 #include "nsNPAPIPlugin.h"
 
 #ifdef XP_WIN
+#include "COMMessageFilter.h"
 #include "nsWindowsDllInterceptor.h"
 #include "mozilla/widget/AudioSession.h"
 #endif
 
 #ifdef MOZ_WIDGET_COCOA
 #include "PluginInterposeOSX.h"
 #include "PluginUtilsOSX.h"
 #endif
@@ -258,16 +259,20 @@ PluginModuleChild::RecvDisableFlashProte
 }
 
 bool
 PluginModuleChild::InitForChrome(const std::string& aPluginFilename,
                                  base::ProcessHandle aParentProcessHandle,
                                  MessageLoop* aIOLoop,
                                  IPC::Channel* aChannel)
 {
+#ifdef XP_WIN
+    COMMessageFilter::Initialize(this);
+#endif
+
     NS_ASSERTION(aChannel, "need a channel");
 
     if (!InitGraphics())
         return false;
 
     mPluginFilename = aPluginFilename.c_str();
     nsCOMPtr<nsIFile> localFile;
     NS_NewLocalFile(NS_ConvertUTF8toUTF16(mPluginFilename),
--- a/dom/plugins/ipc/moz.build
+++ b/dom/plugins/ipc/moz.build
@@ -45,16 +45,17 @@ EXPORTS.mozilla.plugins += [
     'TaskFactory.h',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     EXPORTS.mozilla.plugins += [
         'PluginSurfaceParent.h',
     ]
     UNIFIED_SOURCES += [
+        'COMMessageFilter.cpp',
         'PluginHangUIParent.cpp',
         'PluginSurfaceParent.cpp',
     ]
     SOURCES += [
         'MiniShmParent.cpp', # Issues with CreateEvent
     ]
     DEFINES['MOZ_HANGUI_PROCESS_NAME'] = '"plugin-hang-ui%s"' % CONFIG['BIN_SUFFIX']
     LOCAL_INCLUDES += [
--- a/ipc/glue/WindowsMessageLoop.cpp
+++ b/ipc/glue/WindowsMessageLoop.cpp
@@ -99,17 +99,16 @@ nsTArray<HWND>* gNeuteredWindows = nullp
 
 typedef nsTArray<nsAutoPtr<DeferredMessage> > DeferredMessageArray;
 DeferredMessageArray* gDeferredMessages = nullptr;
 
 HHOOK gDeferredGetMsgHook = nullptr;
 HHOOK gDeferredCallWndProcHook = nullptr;
 
 DWORD gUIThreadId = 0;
-HWND gCOMWindow = 0;
 
 // WM_GETOBJECT id pulled from uia headers
 #define MOZOBJID_UIAROOT -25
 
 LRESULT CALLBACK
 DeferredMessageHook(int nCode,
                     WPARAM wParam,
                     LPARAM lParam)
@@ -336,25 +335,23 @@ ProcessOrDeferMessage(HWND hwnd,
       return 0;
 
     // We only support a query for our IAccessible or UIA pointers.
     // This should be safe, and needs to be sync.
 #if defined(ACCESSIBILITY)
    case WM_GETOBJECT: {
       if (!::GetPropW(hwnd, k3rdPartyWindowProp)) {
         DWORD objId = static_cast<DWORD>(lParam);
-        if ((objId == OBJID_CLIENT || objId == MOZOBJID_UIAROOT)) {
-          WNDPROC oldWndProc = (WNDPROC)GetProp(hwnd, kOldWndProcProp);
-          if (oldWndProc) {
-            return CallWindowProcW(oldWndProc, hwnd, uMsg, wParam, lParam);
-          }
+        WNDPROC oldWndProc = (WNDPROC)GetProp(hwnd, kOldWndProcProp);
+        if ((objId == OBJID_CLIENT || objId == MOZOBJID_UIAROOT) && oldWndProc) {
+          return CallWindowProcW(oldWndProc, hwnd, uMsg, wParam, lParam);
         }
       }
-      return DefWindowProc(hwnd, uMsg, wParam, lParam);
-   }
+      break;
+    }
 #endif // ACCESSIBILITY
 
     default: {
       // Unknown messages only are logged in debug builds and sent to
       // DefWindowProc.
       if (uMsg && uMsg == mozilla::widget::sAppShellGeckoMsgId) {
         // Widget's registered native event callback
         deferred = new DeferredSendMessage(hwnd, uMsg, wParam, lParam);
@@ -645,20 +642,17 @@ namespace windows {
 
 void
 InitUIThread()
 {
   // If we aren't setup before a call to NotifyWorkerThread, we'll hang
   // on startup.
   if (!gUIThreadId) {
     gUIThreadId = GetCurrentThreadId();
-
-    CoInitialize(nullptr);
   }
-
   MOZ_ASSERT(gUIThreadId);
   MOZ_ASSERT(gUIThreadId == GetCurrentThreadId(),
              "Called InitUIThread multiple times on different threads!");
 }
 
 } // namespace windows
 } // namespace ipc
 } // namespace mozilla
@@ -805,31 +799,16 @@ MessageChannel::SpinInternalEventLoop()
 
 static inline bool
 IsTimeoutExpired(PRIntervalTime aStart, PRIntervalTime aTimeout)
 {
   return (aTimeout != PR_INTERVAL_NO_TIMEOUT) &&
     (aTimeout <= (PR_IntervalNow() - aStart));
 }
 
-HWND
-FindCOMWindow()
-{
-  MOZ_ASSERT(gUIThreadId);
-
-  HWND last = 0;
-  while ((last = FindWindowExW(HWND_MESSAGE, last, L"OleMainThreadWndClass", NULL))) {
-    if (GetWindowThreadProcessId(last, NULL) == gUIThreadId) {
-      return last;
-    }
-  }
-
-  return (HWND)0;
-}
-
 bool
 MessageChannel::WaitForSyncNotify()
 {
   mMonitor->AssertCurrentThreadOwns();
 
   MOZ_ASSERT(gUIThreadId, "InitUIThread was not called!");
 
   // Use a blocking wait if this channel does not require
@@ -860,22 +839,16 @@ MessageChannel::WaitForSyncNotify()
 
   NS_ASSERTION(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION,
                "Shouldn't be here for channels that don't use message deferral!");
   NS_ASSERTION(mTopFrame && !mTopFrame->mInterrupt,
                "Top frame is not a sync frame!");
 
   MonitorAutoUnlock unlock(*mMonitor);
 
-  MOZ_ASSERT_IF(gCOMWindow, FindCOMWindow() == gCOMWindow);
-
-  if (!gCOMWindow) {
-    gCOMWindow = FindCOMWindow();
-  }
-
   bool timedout = false;
 
   UINT_PTR timerId = 0;
   TimeoutData timeoutData = { 0 };
 
   if (mTimeoutMs != kNoTimeout) {
     InitTimeoutData(&timeoutData, mTimeoutMs);
 
@@ -934,30 +907,21 @@ MessageChannel::WaitForSyncNotify()
       // PeekMessage will return false if there are no "queued" messages, but it
       // will run all "nonqueued" messages before returning. So if PeekMessage
       // returns false and there are no "nonqueued" messages that were run then
       // we know that the message we woke for was intended for a window on
       // another thread.
       bool haveSentMessagesPending =
         (HIWORD(GetQueueStatus(QS_SENDMESSAGE)) & QS_SENDMESSAGE) != 0;
 
-      // Either of the PeekMessage calls below will actually process all
-      // "nonqueued" messages that are pending before returning. If we have
-      // "nonqueued" messages pending then we should have switched out all the
-      // window procedures above. In that case this PeekMessage call won't
-      // actually cause any mozilla code (or plugin code) to run.
-
-      // We have to manually pump all COM messages *after* looking at the queue
-      // queue status but before yielding our thread below.
-      if (gCOMWindow) {
-        if (PeekMessageW(&msg, gCOMWindow, 0, 0, PM_REMOVE)) {
-          TranslateMessage(&msg);
-          ::DispatchMessageW(&msg);
-        }
-      }
+      // This PeekMessage call will actually process all "nonqueued" messages
+      // that are pending before returning. If we have "nonqueued" messages
+      // pending then we should have switched out all the window procedures
+      // above. In that case this PeekMessage call won't actually cause any
+      // mozilla code (or plugin code) to run.
 
       // If the following PeekMessage call fails to return a message for us (and
       // returns false) and we didn't run any "nonqueued" messages then we must
       // have woken up for a message designated for a window in another thread.
       // If we loop immediately then we could enter a tight loop, so we'll give
       // up our time slice here to let the child process its message.
       if (!PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE) &&
           !haveSentMessagesPending) {
@@ -1009,22 +973,16 @@ MessageChannel::WaitForInterruptNotify()
 
   NS_ASSERTION(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION,
                "Shouldn't be here for channels that don't use message deferral!");
   NS_ASSERTION(mTopFrame && mTopFrame->mInterrupt,
                "Top frame is not a sync frame!");
 
   MonitorAutoUnlock unlock(*mMonitor);
 
-  MOZ_ASSERT_IF(gCOMWindow, FindCOMWindow() == gCOMWindow);
-
-  if (!gCOMWindow) {
-    gCOMWindow = FindCOMWindow();
-  }
-
   bool timedout = false;
 
   UINT_PTR timerId = 0;
   TimeoutData timeoutData = { 0 };
 
   // windowHook is used as a flag variable for the loop below: if it is set
   // and we start to spin a nested event loop, we need to clear the hook and
   // process deferred/pending messages.
@@ -1104,24 +1062,16 @@ MessageChannel::WaitForInterruptNotify()
       timedout = true;
       break;
     }
 
     // See MessageChannel's WaitFor*Notify for details.
     bool haveSentMessagesPending =
       (HIWORD(GetQueueStatus(QS_SENDMESSAGE)) & QS_SENDMESSAGE) != 0;
 
-    // Run all COM messages *after* looking at the queue status.
-    if (gCOMWindow) {
-        if (PeekMessageW(&msg, gCOMWindow, 0, 0, PM_REMOVE)) {
-            TranslateMessage(&msg);
-            ::DispatchMessageW(&msg);
-        }
-    }
-
     // PeekMessage markes the messages as "old" so that they don't wake up
     // MsgWaitForMultipleObjects every time.
     if (!PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE) &&
         !haveSentMessagesPending) {
       // Message was for child, we should wait a bit.
       SwitchToThread();
     }
   }
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -4139,18 +4139,18 @@ nsWindow::IsAsyncResponseEvent(UINT aMsg
 #endif
 
   return false;
 }
 
 void
 nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam)
 {
-  MOZ_ASSERT_IF(msg != WM_GETOBJECT,
-                !mozilla::ipc::MessageChannel::IsPumpingMessages());
+  NS_ASSERTION(!mozilla::ipc::MessageChannel::IsPumpingMessages(),
+               "Failed to prevent a nonqueued message from running!");
 
   // Modal UI being displayed in windowless plugins.
   if (mozilla::ipc::MessageChannel::IsSpinLoopActive() &&
       (InSendMessageEx(nullptr) & (ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
     LRESULT res;
     if (IsAsyncResponseEvent(msg, res)) {
       ReplyMessage(res);
     }