Bug 1465466 Part 5 - Don't use APZ in recording/replaying processes, r=kats,mconley.
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2044,29 +2044,29 @@ ContentParent::NotifyTabDestroyed(const
}
}
mozilla::ipc::IPCResult
ContentParent::RecvOpenRecordReplayChannel(const uint32_t& aChannelId,
FileDescriptor* aConnection)
{
// We should only get this message from the child if it is recording or replaying.
- if (!recordreplay::IsRecordingOrReplaying()) {
+ if (!this->IsRecordingOrReplaying()) {
return IPC_FAIL_NO_REASON(this);
}
recordreplay::parent::OpenChannel(Pid(), aChannelId, aConnection);
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvCreateReplayingProcess(const uint32_t& aChannelId)
{
// We should only get this message from the child if it is recording or replaying.
- if (!recordreplay::IsRecordingOrReplaying()) {
+ if (!this->IsRecordingOrReplaying()) {
return IPC_FAIL_NO_REASON(this);
}
while (aChannelId >= mReplayingChildren.length()) {
if (!mReplayingChildren.append(nullptr)) {
return IPC_FAIL_NO_REASON(this);
}
}
@@ -2087,17 +2087,17 @@ ContentParent::RecvCreateReplayingProces
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvTerminateReplayingProcess(const uint32_t& aChannelId)
{
// We should only get this message from the child if it is recording or replaying.
- if (!recordreplay::IsRecordingOrReplaying()) {
+ if (!this->IsRecordingOrReplaying()) {
return IPC_FAIL_NO_REASON(this);
}
if (aChannelId < mReplayingChildren.length() && mReplayingChildren[aChannelId]) {
DelayedDeleteSubprocess(mReplayingChildren[aChannelId]);
mReplayingChildren[aChannelId] = nullptr;
}
return IPC_OK();
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1263,16 +1263,20 @@ public:
const bool& aAnonymize,
const bool& aMinimizeMemoryUsage,
const MaybeFileDesc& aDMDFile) override;
bool CanCommunicateWith(ContentParentId aOtherProcess);
nsresult SaveRecording(nsIFile* aFile, bool* aRetval);
+ bool IsRecordingOrReplaying() const {
+ return mRecordReplayState != eNotRecordingOrReplaying;
+ }
+
private:
// If you add strong pointers to cycle collected objects here, be sure to
// release these objects in ShutDownProcess. See the comment there for more
// details.
ContentProcessHost* mSubprocess;
const TimeStamp mLaunchTS; // used to calculate time to start content process
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -170,16 +170,17 @@ TabParent::TabParent(nsIContentParent* a
#endif
, mLayerTreeEpoch(1)
, mPreserveLayers(false)
, mRenderLayers(true)
, mHasLayers(false)
, mHasPresented(false)
, mHasBeforeUnload(false)
, mIsMouseEnterIntoWidgetEventSuppressed(false)
+ , mIsActiveRecordReplayTab(false)
{
MOZ_ASSERT(aManager);
// When the input event queue is disabled, we don't need to handle the case
// that some input events are dispatched before PBrowserConstructor.
mIsReadyToHandleInputEvents = !ContentParent::IsInputEventQueueSupported();
}
TabParent::~TabParent()
@@ -369,16 +370,18 @@ TabParent::DestroyInternal()
// is shut down.
const ManagedContainer<PPluginWidgetParent>& kids =
ManagedPPluginWidgetParent();
for (auto iter = kids.ConstIter(); !iter.Done(); iter.Next()) {
static_cast<mozilla::plugins::PluginWidgetParent*>(
iter.Get()->GetKey())->ParentDestroy();
}
#endif
+
+ SetIsActiveRecordReplayTab(false);
}
void
TabParent::Destroy()
{
// Aggressively release the window to avoid leaking the world in shutdown
// corner cases.
mBrowserDOMWindow = nullptr;
@@ -2869,16 +2872,21 @@ TabParent::SetDocShellIsActive(bool isAc
}
}
#endif
// Let's inform the priority manager. This operation can end up with the
// changing of the process priority.
ProcessPriorityManager::TabActivityChanged(this, isActive);
+ // Keep track of how many active recording/replaying tabs there are.
+ if (Manager()->AsContentParent()->IsRecordingOrReplaying()) {
+ SetIsActiveRecordReplayTab(isActive);
+ }
+
return NS_OK;
}
NS_IMETHODIMP
TabParent::GetDocShellIsActive(bool* aIsActive)
{
*aIsActive = mDocShellIsActive;
return NS_OK;
@@ -3587,16 +3595,27 @@ TabParent::LiveResizeStarted()
}
void
TabParent::LiveResizeStopped()
{
SuppressDisplayport(false);
}
+/* static */ size_t TabParent::gNumActiveRecordReplayTabs;
+
+void
+TabParent::SetIsActiveRecordReplayTab(bool aIsActive)
+{
+ if (aIsActive != mIsActiveRecordReplayTab) {
+ gNumActiveRecordReplayTabs += aIsActive ? 1 : -1;
+ mIsActiveRecordReplayTab = aIsActive;
+ }
+}
+
NS_IMETHODIMP
FakeChannel::OnAuthAvailable(nsISupports *aContext, nsIAuthInformation *aAuthInfo)
{
nsAuthInformationHolder* holder =
static_cast<nsAuthInformationHolder*>(aAuthInfo);
if (!net::gNeckoChild->SendOnAuthAvailable(mCallbackId,
holder->User(),
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -586,16 +586,20 @@ public:
// LiveResizeListener implementation
void LiveResizeStarted() override;
void LiveResizeStopped() override;
void SetReadyToHandleInputEvents() { mIsReadyToHandleInputEvents = true; }
bool IsReadyToHandleInputEvents() { return mIsReadyToHandleInputEvents; }
+ static bool AreRecordReplayTabsActive() {
+ return gNumActiveRecordReplayTabs != 0;
+ }
+
protected:
bool ReceiveMessage(const nsString& aMessage,
bool aSync,
ipc::StructuredCloneData* aData,
mozilla::jsipc::CpowHolder* aCpows,
nsIPrincipal* aPrincipal,
nsTArray<ipc::StructuredCloneData>* aJSONRetVal = nullptr);
@@ -781,16 +785,25 @@ private:
// True when the remote browser is created and ready to handle input events.
bool mIsReadyToHandleInputEvents;
// True if we suppress the eMouseEnterIntoWidget event due to the TabChild was
// not ready to handle it. We will resend it when the next time we fire a
// mouse event and the TabChild is ready.
bool mIsMouseEnterIntoWidgetEventSuppressed;
+ // How many record/replay tabs have active docshells in this process.
+ static size_t gNumActiveRecordReplayTabs;
+
+ // Whether this tab is contributing to gNumActiveRecordReplayTabs.
+ bool mIsActiveRecordReplayTab;
+
+ // Update whether this is an active record/replay tab.
+ void SetIsActiveRecordReplayTab(bool aIsActive);
+
public:
static TabParent* GetTabParentFromLayersId(layers::LayersId aLayersId);
};
struct MOZ_STACK_CLASS TabParent::AutoUseNewTab final
{
public:
AutoUseNewTab(TabParent* aNewTab, nsCString* aURLToLoad)
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -11,16 +11,17 @@
#include "Compositor.h" // for Compositor
#include "DragTracker.h" // for DragTracker
#include "gfxPrefs.h" // for gfxPrefs
#include "HitTestingTreeNode.h" // for HitTestingTreeNode
#include "InputBlockState.h" // for InputBlockState
#include "InputData.h" // for InputData, etc
#include "Layers.h" // for Layer, etc
#include "mozilla/dom/MouseEventBinding.h" // for MouseEvent constants
+#include "mozilla/dom/TabParent.h" // for AreRecordReplayTabsActive
#include "mozilla/dom/Touch.h" // for Touch
#include "mozilla/gfx/gfxVars.h" // for gfxVars
#include "mozilla/gfx/GPUParent.h" // for GPUParent
#include "mozilla/gfx/Logging.h" // for gfx::TreeLog
#include "mozilla/gfx/Point.h" // for Point
#include "mozilla/layers/APZSampler.h" // for APZSampler
#include "mozilla/layers/APZThreadUtils.h" // for AssertOnControllerThread, etc
#include "mozilla/layers/APZUpdater.h" // for APZUpdater
@@ -1131,16 +1132,23 @@ APZCTreeManager::FlushApzRepaints(Layers
nsEventStatus
APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutInputBlockId)
{
APZThreadUtils::AssertOnControllerThread();
+ // Ignore input events when there are active tabs that are recording or
+ // replaying. APZ does not work with the special layers constructed by
+ // the middleman processes being communicated with here.
+ if (dom::TabParent::AreRecordReplayTabsActive()) {
+ return nsEventStatus_eIgnore;
+ }
+
// Use a RAII class for updating the focus sequence number of this event
AutoFocusSequenceNumberSetter focusSetter(mFocusState, aEvent);
#if defined(MOZ_WIDGET_ANDROID)
MOZ_ASSERT(mToolbarAnimator);
ScreenPoint scrollOffset;
{
RecursiveMutexAutoLock lock(mTreeLock);